记一次服务器迁移记录

记一次服务器迁移记录

最近emufan.com的备案被注销了.而且部署在github上访问和收录都有点不稳定.于是想搬个服务器. 一来是备案不太方便.年初的时候在阿里云备案还不需要邮寄资料.这次还需要邮寄资料.太麻烦了.而且目前并不太在意访问速度..话说目前访问速度很慢么?

挑选服务器

一开始选择了香港的服务器.但是后来想想.香港服务器又贵.性能又不太好.带宽低.而且速度访问有时候还是挺慢的(通常都不错).结合自己的开发和需求最终选择了国外.
那么问题来了.选择国外如何选择最优质的服务器?这里去网上查询了一下 发现大家都首推linode..不过不支持PayPal付款..这点就蛋疼了..后来再三挑选下终究选择了digitalocean
点我送$10

因为是点击朋友的注册.所以送了$10.再加上自己购买的是1cpu/1G/30G/2T服务器,加上备份快照服务费一个月才$12.5
注册后便可以开始创建服务器了

服务器性能测试

这里创建的是centos7.2. 安装好mongodb,lnmp,nvm(nodejs版本管理工具)后就可以开始服务器性能测试了.
因为服务器用的是SSD固态硬盘.所以读写速度可以达到700mb/s(待长期测试).至于带宽的话 我选择的是新加坡机房.最高速度给我达到了5m/s(从七牛华北cdn下载备份文件) 卧槽..这简直不敢想象啊….用习惯了国内的128kb/s 一时间还不习惯这么高的下载速度..

服务器备份

说实在话当初选择了这家还是看重了一下服务器备份方面.发现这家服务商会每周自动备份一次.然后还会提供快照功能..虽然没阿里云那么强大.但是也够用了

迁移数据

把原服务器的/home/ 备份到一个文件后 然后利用原服务器上传到七牛cdn去(tools:qsshell) 上传上去后 再通过目前的服务器down下载下来.. 然后解压.
接着用phpmyadmin把sql备份下来.备份的时候记得选择添加create语句. 为了保持数据的一致性.所以账号密码都保持原状.这样就不需要做更多的修改了

启动服务

首先把vhost下的所有文件copy到新服务器去.然后重启lnmp 接着安装pm2工具 这样可以持久化启动nodejs.

同步博客内容

首先博客是部署在github上的.为了保持接口的一致性,即不需要修改原博客的上传地址和git地址. 于是在上传的时候去动态调用一下新服务器的接口 新服务器的接口监听到事件后同步github的内容.为了保证服务器不会出现合并冲突问题.我们只需要保证服务器中同步的内容始终是新内容即可

Generator控制sprity合并

Generator控制sprity合并

gulp-sprity是一个不错的插件.但是有一点问题

1.生成sass与less的时候所有的变量都在一个less/sass里面.不太好控制和引入

解决方案问题一

一开始是打算直接用for of循环读取数组内容然后直接生成的.但是这样会带来一点问题.如果上一次的内容没有生成,立即执行下一次内容生成会导致出现1.的情况..虽然你生成了两个文件.但是两个文件都是一样的内容..

控制异步流程

其根本问题在于异步的流程控制.那么如何控制数组中的异步流程?
其实就是.你想要函数执行第一次后再去执行接下来的.那么这里就可以用Generator来控制
数组是自带了Symbol.iterator 这个Symbol.iterator实际上就是一个Generator
那么就可以写一个函数每次结束后再去next.

如何监听gulp.pipe结束

一开始是打算使用.on(‘end’)事件..结果毛用都没.仔细研究和翻阅文档下.发现unpipe和finish这个事件是可以监听到的.
end是针对于read,finish是针对于写事件.那么这下就好办了.递归循环即可

最终代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"use strict";
const gulp = require("gulp");
const sass = require("gulp-sass");
const gulpif = require("gulp-if");
const sprity = require("sprity");
const clean = require("gulp-clean");
//const exec=require("children_process").exec;
const sptitesList = require("./files.json");
const cdn="../sprite";
function globalSprites(options,cb) {
options =options|| {
processor: "less",
"style-type": "less",
};
let spritesGen=sptitesList[Symbol.iterator]();
sprityPromise(spritesGen,options);
}
function sprityPromise(result,options){
let{value,done}=result.next();
if(!value){
console.log("合并完成")
return false;
}
console.log("开始合并:",value);
let i= value;
options['src']=`dev/slice/${i}/**/*.{png,jpg}`;
options['style']=`./${i}-sprite.${options.processor}`;
options['name']=`${i}-sprite`;
options['cssPath']=`${cdn}/${i}`;
sprity.src(options)
.pipe(
gulpif("*.png", gulp.dest(`dist/sprite/${i}`), gulp.dest(`dist/${options.processor}/${i}`))
)
.on("finish",()=>{sprityPromise(result,options)})
}
/**
*
* less版本雪碧图合并
*
*/
gulp.task("sprites:less", function (cb) {
globalSprites(null,cb)
});
/**
*
* sass版本雪碧图合并
*
*/
gulp.task("sprites:sass", function (cb) {
let opt={
processor: "sass",
"style-type": "sass",
cssPath: "../sprite"
};
globalSprites(opt,cb)
});
/**
*
* css版本雪碧图合并
*
*/
gulp.task("sprites:css", function (cb) {
let opt={
processor: "css",
"style-type": "css",
cssPath: "../sprite"
};
globalSprites(opt,cb)
});

邮箱发送html案例

邮箱发送案例笔记

今天在做邮箱发送案例的时候发现有一些问题需要处理

这里的邮箱指的是QQ邮箱

  1. 避免使用*zoom,*display,*xxx
  2. 避免使用css样式选择器
  3. 规定宽度如650px 利用margin居中
  4. 所有样式内联
  5. 避免使用复杂样式

1.则是因为邮箱在处理的时候会把不标准的css样式给屏蔽掉.所以导致*xxx 以后的样式全部无效.如果要用请把*xxx放在最后进行处理

2.和4.可以先利用选择器写好然后再利用gulp脚本自动生成,这里给出一段,所需模块已经require,需要的可以直接去npm进行下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const gulp=require("gulp");
const inlineCss=require("gulp-inline-css");
const rename=require("gulp-rename");
module.exports=function () {
gulp.task("inlineCss",()=>{
return gulp.src("./dist/html/微信邀请函/*.html")
.pipe(inlineCss())
.pipe(rename((path)=>{
path.dirname="./";
path.basename+="-inline-css";
}))
.pipe(gulp.dest("./dist/html/微信邀请函/inlineCss/"))
})
};
  1. 则是因为避免不同屏幕大小下的问题.这里给出一个参考值650px

VuexDemo学习记录

VuexDemo学习记录

Vuex官方提供了一个很简单的demo来演示vuex的数据流,这里先对Vuex的demo进行一个简单的分析和理解

文件目录

  • /
  • main.js
  • app.vue
  • /vuex
    • action.js
    • getters.js
    • store.js
  • components
    • Display.vue
    • Increment.vue

vuex

vuex的数据流可以用三句话解决

用户在组件中的输入操作触发 action 调用;

Actions 通过分发 mutations 来修改 store 实例的状态;

Store 实例的状态变化反过来又通过 getters 被组件获知。

store

首先在store.js中声明 state以及mutations
其中state是用来放数据的,mutations则是用来放触发事件 当执行action的时候 action再去触发mutations

action

在actions.js则只声明了一个函数,这个函数的作用仅仅是用来调用mutaions 传递对应的参数给mcations

getter

vue提供了getter方法,当需要显示数据的时候,首先是调用数据的getter方法.那么在获取数据之前就可以利用getter方法对数据进行处理方便后续开发.

getter.js也仅仅是声明了一个函数 这个函数返回的是state中的内容.

那么这个传递过来的state参数是哪来的?
其实getter不关心是谁引用了 只关心有没有state.xxx 这个属性.所以这个state是由父级(此例是APP.vue)的store属性来控制的

Display.Vue

这个Vue组件仅仅做展示, 那么这里的展示就涉及到了一个共享数据 展示数据从哪里来?

很显然,展示的数据是共享的,所以展示的数据是从state中拿的,那么涉及到拿数据,肯定就需要getter.js来帮忙处理了

Increment.vue

这个Vue组件是用来执行actions的.
也就是这里的函数会调用actions.js 再由actions来触发mutations中的事件.

APP.vue

这里的App.vue
也就是用来引入组件模块,同时用来控制 子组件到底引入那个store

假如子组件在不同的父组件中,store也不可能一样吧.所以父组件就规定了store.

那么子组件的子组件,store如何控制呢?

实际上当父组件引用了a.store 子组件引用了b.store 其子组件显示的store是b.store 而不是a.

数据流图

规范

  1. 应用 state 存在于单个对象中;
  2. 只有 mutation handlers 可以改变 state;
  3. Mutations 必须是同步的,它们做的应该仅仅是改变 state;
  4. 所有类似数据获取的异步操作细节都应封装在 actions 里面。
  5. 组件通过 getters 从 store 中获取 state,并通过调用 actions 来改变 state。

Vuex actions 和 mutations 优雅的地方在于它们都只是一些函数。只需要遵循以上的准则,怎么组织代码就取决于你自己了。

应用结构

mongoose使用原始mongodb带auth

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var dbUrl="mongodb://username:pw@localhost:27017/dbname";
var db=mongoose.createConnection(dbUrl);
db.on("open",function(){
console.log("open");
mongoose.connection.db.collection("sessions", function (err, collection) {
console.log("is open db ")
collection.find({_id: sid}).toArray(function (err, results) {
//console.log('session',err,results)
if (!results.length||err) {
return false
} else {
socket.session = JSON.parse(results[0].session)
console.log(23, socket.session)
next()
}
});
});
})

剩下的跟mongodb原始查询语法一样. 需要在db.open以后再进行查询

maclaravel failed to open stream Permission denied

laravel5

因为直接从win下copy目录 然后不知道改动了啥导致出现open stream: Permission denied 错误 经过一个多小时候的探索发现
参考这篇文章

1
2
3
4
5
6
7
php artisan cache:clear
chmod -R 777 storage
composer dump-autoload
composer update

然后出现另外一种错误
Please provide a valid cache path.

参考

接着在storage/framework 下面创建 sessions, views, cache 文件夹 搞定
如果framework文件夹没有那么就创建他

MAC安装proxychains-ng实现terminal-socks5代理

安装brew

1
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

brew安装proxychains-ng

1
brew install proxychains-ng

修改配置文件

1
vim /usr/local/etc/proxychains.conf

在最下面一行 socks4 xxx.xxx.xxx.xxx 改为相应的协议 比如 sock5 127.0.0.1 1080

使用代理连接

1
proxychains4 npm install;

mac安装lnmp环境

参考教程

安装brew

1
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装PHP5.6

1
2
3
4
5
6
7
8
9
10
11
brew install php56 \
--without-snmp \
--without-apache \
--with-fpm \
--with-intl \
--with-homebrew-curl \
--with-homebrew-libxslt \
--with-homebrew-openssl \
--with-imap \
--with-mysql \
--with-tidy`

不要用–without-debug方式安装 否则会造成php扩展模块编译后与php不兼容

修改系统环境

在~/.bash_profile中添加环境

1
export PATH="/usr/local/bin:/usr/local/sbin:$PATH"

安装php56扩展

1
brew install php56-gearman php56-msgpack php56-memcache php56-memcached php56-mongo php56-phalcon php56-redis php56-xdebug

安装nginx

1
brew install nginx

剩下的请去原博文进行查看 只需要注意 编译的时候不要用debug模式编译

wordpress查询

WP_Query

获取当前页面内容

1
2
3
$now_id=get_the_ID();
$now_post=get_post($now_id);
$now_content=$now_post->post_content;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
获取当前文章内容,根据文章内容来获取
*/
$now_id=get_the_ID();
$now_post=get_post($now_id);
$now_content=$now_post->post_content;
$content_json=json_decode($now_content,true);
//print_r($content_json);
$text_title=$content_json["title"];
$text_small=$content_json["title-small"];
$category_text=$content_json["category"];
$args = array(
'post_type' => 'post',
'showposts' => 8,
"category_name"=>$category_text,
'orderby' => 'date',
'paged' => $paged,
);
$loop = new WP_Query($args);

查询说明

1
2
3
4
5
6
7
$args = array(
'post_type' => 'post',
'showposts' => 8,
"category_name"=>$category_text,
'orderby' => 'date',
'paged' => $paged,
);

post_type为查询类型
category_name为文章的别名

剩下的看API即可..以后会逐步更新

mongodb3.0配置权限漏洞修复方案

阿里云中的mongodb配置漏洞

在阿里云看到的mongodb配置漏洞其中的手动解决方案已经不适用于目前的3.x版本的mongodb.于是这边找了一下资料写一个简单的教程

原因

mongodb之所以会产生的原因还是在于平时我们启动mongodb都是直接mongod –dbpath启动的. 这种启动方式是没有用户名和密码验证的.所以会导致某些用户可以不经过授权直接访问数据库内容.解决方案也很简单 加上-auth即可