阿里云VPS搭建自己的的Hexo博客

1. 博客的架构

先搞明白Hexo博客从搭建到自动发布的架构,才能更好的理解我们每一步进行的操作。
不然只跟着步骤过了一遍,却不知道为什么这么做。

首先看这张架构图:
Hexo-Structure

整个流程就是本地将 *.md 渲染成静态文件,然后Git推送到服务器的repository,服务器再通过 git-hooks 同步网站根目录。

2. 整个搭建流程

第一部分: 服务器环境搭建,包括安装 GitNginx配置 、创建 git 用户 。

第二部分: 本地Hexo初始化, 包括安装 NodeJShexo-cli, 生成本地静态网站

第三部分: 使用Git自动化部署发布博客

3. 服务器环境搭建

3-1.安装Git和NodeJS (CentOS 环境)

1
2
3
yum install git
#安装NodeJS
curl --silent --location https://rpm.nodesource.com/setup_5.x | bash -

NodeJS 安装可以参考: Linux安装NodeJS

3-2. 创建git用户

1
2
3
adduser git
chmod 740 /etc/sudoers
vim /etc/sudoers

找到以下内容

1
2
## Allow root to run any commands anywhere
root ALL=(ALL) ALL

在下面添加一行

1
git   ALL=(ALL)     ALL

保存退出后改回权限

1
chmod 400 /etc/sudoers

随后设置Git用户的密码,

1
2
#需要root权限
sudo passwd git

切换至git用户,创建 ~/.ssh 文件夹和 ~/.ssh/authorized_keys文件,并赋予相应的权限

1
2
3
4
5
6
su git
mkdir ~/.ssh
vim ~/.ssh/authorized_keys
#然后将电脑中执行 cat ~/.ssh/id_rsa.pub | pbcopy ,将公钥复制粘贴到authorized_keys
chmod 600 ~/.ssh/authorzied_keys
chmod 700 ~/.ssh

然后就可以执行ssh 命令测试是否可以免密登录

1
ssh -v git@SERVER

至此,Git用户添加完成

3-3. Nginx安装和配置

我是用的是lnmp 一键安装包,nginx安装教程一大堆,就不再叙述。主要看nginx配置。
找到nginx的配置文件,修改配置如下:

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
server
{
listen 80;
#listen [::]:80;
server_name www.seekbetter.me seekbetter.me;
index index.html index.htm index.php default.html default.htm default.php;
#这里要改成网站的根目录
root /path/to/www;

include other.conf;
#error_page 404 /404.html;
location ~ .*\.(ico|gif|jpg|jpeg|png|bmp|swf)$
{
access_log off;
expires 1d;
}

location ~ .*\.(js|css|txt|xml)?$
{
access_log off;
expires 12h;
}

location / {
try_files $uri $uri/ =404;
}

access_log /home/wwwlogs/blog.log access;
}

4. 本地Hexo程序

4-1:初始化Hexo博客

首先要安装 hexo-cli,安装hexo-cli 需要 root 权限,使用 sudo 运行

1
sudo npm install -g hexo-cli

然后初始化Hexo程序

1
2
cd ~/Documents/code
hexo init blog

等执行成功以后安装两个插件, hexo-deployer-githexo-server ,这俩插件的作用分别是使用Git自动部署,和本地简单的服务器。

hexo-deployer-git帮助文档
hexo-server帮助文档

1
2
3
cd blog
npm install hexo-deployer-git
npm install hexo-server

4-2. 生成自己的第一篇文章 hello world !

使用 hexo new <文章名称> 来新建文章,该命令会成成一个 .md文件放置在 sources/_posts文件夹。

1
2
hexo new "hello Hexo"
vim sources/_posts/hello-hexo.md

编辑完毕以后, 使用hexo g.md文件渲染成静态文件,然后启动hexo-server

1
2
hexo g
hexo server

现在便可以打开浏览器访问 http://localhost:4000 来查看我们的博客了!

5. 自动化部署

5-1:服务器上建立git裸库

创建一个裸仓库,裸仓库就是只保存git信息的Repository, 首先切换到git用户确保git用户拥有仓库所有权
一定要加 --bare,这样才是一个裸库。

1
2
3
su git
cd ~
git init --bare blog.git

5-2. 使用 git-hooks 同步网站根目录

在这里我们使用的是 post-receive这个钩子,当git有收发的时候就会调用这个钩子。 在 ~/blog.git 裸库的 hooks文件夹中,
新建post-receive文件。

1
2
3
4
vim ~/blog.git/hooks/post-receive

#!/bin/sh
git --work-tree=/path/to/www --git-dir=~/blog.git checkout -f

保存后,要赋予这个文件可执行权限

1
chmod +x post-receive

5-3. 配置_config.yml,完成自动化部署

然后打开 _config.yml, 找到 deploy

1
2
3
4
5
deploy:
type: git
repo: git@SERVER:/home/git/blog.git //<repository url>
branch: master //这里填写分支 [branch]
message: 提交的信息 //自定义提交信息 (默认为 Site updated: {{ now('YYYY-MM-DD HH:mm:ss') }})

保存后,尝试将我们刚才写的”hello hexo”部署到服务器

1
2
hexo clean
hexo generate --delpoy

访问服务器地址,就可以看到我们写的文章”Hello hexo”,以后写文章只需要:

1
2
3
hexo new "Blog article name"
···写文章
hexo clean && hexo generate --deploy

博客就更新咯!~

参考资料:

使用 Git Hook 自动部署 Hexo 到个人 VPS
Hexo 文档

数据库及迁移规范

1. Migrations 起名规则

表名_动作_字段, 动作包括 create, add, delete ,alter。 这样起名的好处是,比较好查找一个表的改动。

如果改变了多个字段, 仅需要写其中一个字段的名称即可。

1
[table_name]_[action]_[column]

示例:

  1. 增加一个example_table 表,因为他没有影响字段,则命名为:

    1
    example_table_create
  2. example表中添加一个字段 user_name, 命名为:

    1
    example_table_add_user_name
  3. 修改 example_table 表中的 user_name , 命名为:

    1
    example_table_alter_user_name

2. Migrations 书写规范

  1. 如果是 create 生成表的 migration , 需要在头部添加注释, 解释该表的作用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    <?php

    /*
    * 该表主要是用来示范注释, 说明这个表的作用
    * author: 小黑
    * time: 2015-11-11 18:09
    */

    class m151002_121202_example_table_create extends CDbMigration
    {

    ·····
    }
  2. 在一些需要有默认值的字段,请务必加上 Default

  • 所有字段的定义都需要加上注释
  • 非空原则:所有字段均不可为 NULL
  • 字符型的默认值为一个空字符值串 ‘ ‘ ;
  • 数值型的默认值为数值0;逻辑型的默认值为数值0

    1
    2
    3
    4
    5
    public function up()
    {

    //用户是否是新用户字段
    $this->addColumn("wx_user", 'is_new', 'integer(1) NOT NULL DEFAULT 0 COMMENT "是否是新用户"');
    }

Mac上安装Nginx+PHP5.6+MySQL+NodeJS+Express

1. 安装Homebrew

如果已经安装,请跳到下一步

HomebrewOSX 上注明的软件包管理器, 可以方便的安装很多常用软件。安装过程很简单,运行一下命令即可。

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

安装完毕以后,由于Homebrew可以能会做一些编译的事情,所以需要安装command line tools, 我用的是 10.8.5 Mountain Lion,请在apple的开发者下载中心(https://developer.apple.com/downloads/)选择自己对应的版本进行下载安装。

brew(意为酿酒)的命名很有意思,全部都使用了酿酒过程中采用的材料/器具,名词对应以下的概念:

  • Formula(配方) 程序包定义,本质上是一个rb文件
  • Keg(桶)程序包的安装路径
  • Cellar(地窖)所有程序包(桶)的根目录
  • Tap(水龙头)程序包的源
  • Bottle (瓶子)编译打包好的程序包

最终编译安装完毕的程序就是一桶酿造好的酒, 更多内容请查看官方“酿酒文档”

2. 安装PHP-5.6(FPM模式)

2-1. 首先要添加Homebrew官方的几个软件源,就是 Tap .

添加 homebrew/dupeshomebrew/versions 软件源,这两个软件源有我们需要的依赖包:

1
2
$ brew tap homebrew/dupes
$ brew tap homebrew/versions

最后添加Homebrew 官方的PHP 软件源homebrew-php :

1
$ brew tap homebrew/homebrew-php

2-2. 查看安装参数,选择PHP版本进行安装

TIPS: 可以用一下命令查看安装可选参数

1
$ brew options php56

由于新版的MacOSX会把curl"SSL Version" 设置为SecureTransport, 导致PHP中无法curl访问https的网址, 需要设置 SSL Versionopenssl, 才可以, 所以在安装php之前,首先要安装openssl版本的的curl,

1
brew install curl --with-libssh2 --with-openssl

PHP如果采用默认配置安装,会编译 mod_php 模块并只运行在Apache环境下,为了使用Nginx,这里需要编译 php-fpm 并且禁用apache,主要通过参数--without-fpm --without-apache 来实现。这是我的安装参数:

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

2-3. 安装PHP扩展

有一些很多常用的扩展,我们都可以用Homebrew 来进行安装,可以搜索PHP 查看可以安装的扩展。

1
$ brew search php

【注意] 使用Laravel要求有 mcrypt 扩展,在安装扩展的时候注意, 由于我们安装PHP 的时候,加上了 –with-debug 参数,所以有些扩展安装后无法使用,会报这样的错误:

Warning: PHP Startup: redis: Unable to initialize module
Module compiled with build ID=API20131226,NTS
PHP compiled with build ID=API20131226,NTS,debug
These options need to match in Unknown on line 0

这时候需要在安装扩展的时候,加上 --build-from-source 参数,所以安装 mcrypt 的命令如下:

1
$ brew install mcrypt php56-mcrypt --build-from-source

2-4. 取代内置PHP

由于Mac自带了phpphp-fpm,因此需要添加系统环境变量PATH来替代自带PHP版本。
我使用的是zsh , 所以在 `/.zshrc 中添加下面三行代码:

1
2
3
export PATH="$(brew --prefix php56)/bin:$PATH"
export PATH="$(brew --prefix php56)/sbin:$PATH"
export PATH="/usr/local/bin:/usr/local/sbib:$PATH"

重启终端后,输入 php -v 来验证版本。

2-5. 启动、停止和重启PHP-FPM

修改php-fpm配置文件,

1
vim /usr/local/etc/php/5.5/php-fpm.conf

找到pid相关大概在25行,去掉注释 pid = run/php-fpm.pid, 那么php-fpmpid文件就会自动产生在 /usr/local/var/run/php-fpm.pid ,下面要安装的Nginx pid文件也放在这里。

启动之前可以先测试一下 php-fpm 的配置

1
php-fpm -t

没有问题可以启动啦!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 启动php-fpm
php-fpm -D
OR
php-fpm -c /usr/local/etc/php/5.5/php.ini -y /usr/local/etc/php/5.5/php-fpm.conf -D

# 关闭php-fpm
kill -INT cat /usr/local/var/run/php-fpm.pid

# 重启php-fpm
kill -USR2 cat /usr/local/var/run/php-fpm.pid

# 还可以用这个命令来启动php-fpm
launchctl load -w /Library/LaunchAgents/homebrew.mxcl.php55.plist

# php-fpm 开机自动启动
ln -sfv /usr/local/opt/php55/\*.plist /Library/LaunchAgents
launchctl load /Library/LaunchAgents/homebrew.mxcl.php55.plist

启动php-fpm之后,确保它正常运行监听9000端口:

1
2
3
4
5
6
$ lsof -Pni4 | grep LISTEN | grep php
php-fpm 30907 calvin 9u IPv4 0xf11f9e8e8033a2a7 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 30917 calvin 0u IPv4 0xf11f9e8e8033a2a7 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 30918 calvin 0u IPv4 0xf11f9e8e8033a2a7 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 30919 calvin 0u IPv4 0xf11f9e8e8033a2a7 0t0 TCP 127.0.0.1:9000 (LISTEN)
# 正常情况,会看到上面这些进程

3. 安装 NodeJS+Express

3-1.安装NodeJS

安装NodeJS 真是 hin 简单啊, 一行命令搞定:

1
$ brew install node

3-2.安装Express

使用 npm init 命令,会生成 package.json 文件。

1
$ npm init

这个命令会提示你输入一个应用的名称或者版本号,你可以使用默认的 index.js ,也可以改为 app.js , 不想改的话就直接按回车键。

1
entry point: (index.js)

现在就可以安装了, –save 参数可以讲依赖列表存入package.json.

1
$ npm install express --save

安装好Express后, 编辑 app.js :

1
2
3
4
5
6
7
8
9
10
11
12
13
var express = require('express');
var app = express();

app.get('/', function (req, res) {
res.send('Hello World!');
});

var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;

console.log('Example app listening at http://%s:%s', host, port);
});

然后运行

1
$ node app.js

打开浏览器,输入 http://localhost:3000 , 可以看到Express 已经成功运行。

4. 安装Nginx

还是使用 Homebrew 来安装 Nginx ,

1
$ brew install nginx

4-1.启动Nginx

监听80端口需要有 root 权限, 所以先为 Nginx 添加 root 权限 :

1
2
sudo chown root:wheel /usr/local/Cellar/nginx/1.8.0/bin/nginx
sudo chmod u+s /usr/local/Cellar/nginx/1.8.0/bin/nginx

启动命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 测试配置是否有语法错误
nginx -t

# 打开 nginx
sudo nginx

# 重新加载配置|重启|停止|退出 nginx
nginx -s reload|reopen|stop|quit

# 也可以使用Mac的launchctl来启动|停止
launchctl unload /Library/LaunchAgents/homebrew.mxcl.nginx.plist
launchctl load -w /Library/LaunchAgents/homebrew.mxcl.nginx.plist

# Nginx开机启动
ln -sfv /usr/local/opt/nginx/\*.plist /Library/LaunchAgents
launchctl load /Library/LaunchAgents/homebrew.mxcl.nginx.plist

4-2. Nginx 配置

模仿Ubuntu中的文件夹结构建立文件夹:

1
2
3
4
5
6
mkdir -p /usr/local/etc/nginx/sites-available
mkdir -p /usr/local/etc/nginx/sites-enabled
mkdir -p /usr/local/etc/nginx/conf.d
sudo mkdir -p /var/www
sudo chown :staff /var/www
sudo chmod 775 /var/www

编辑Nginx 全局变量

1
$ vim /usr/local/etc/nginx/nginx.conf
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
worker_processes  1;

error_log /usr/local/var/logs/nginx/error.log debug;


pid /usr/local/var/run/nginx.pid;


events {
worker_connections 256;
}


http {
include mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /usr/local/var/logs/access.log main;

sendfile on;
keepalive_timeout 65;
port_in_redirect off;

include /usr/local/etc/nginx/sites-enabled/*;
}

这样可以把一些可复用配置独立出来放在 /usr/local/etc/nginx/conf.d 下,比如fastcgi的设置就可以独立出来

1
vim /usr/local/etc/nginx/conf.d/php-fpm

内容为:

1
2
3
4
5
6
7
location ~ \.php$ {
try_files $uri 404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_intercept_errors on;
include /usr/local/etc/nginx/fastcgi.conf;
}

然后 /usr/local/etc/nginx/sites-available 目录下可以一个文件对应一个域名的配置,创建默认虚拟主机default

1
vim /usr/local/etc/nginx/sites-available/default

比如服务器目录是/var/www,那么配置为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
listen 80;
server_name localhost;
root /var/www/;

access_log /usr/local/var/logs/nginx/default.access.log main;

location / {
index index.html index.htm index.php;
autoindex on;
include /usr/local/etc/nginx/conf.d/php-fpm;
}

location = /info {
allow 127.0.0.1;
deny all;
rewrite (.*) /.info.php;
}

error_page 404 /404.html;
error_page 403 /403.html;
}

我们还有一个Express实例,所以为它做一个转发。

1
vim /usr/local/etc/nginx/sites-available/express

配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# the IP(s) on which your node server is running. I chose port 3000.
upstream app_yourdomain {
server 127.0.0.1:3000;
keepalive 8;
}

# the nginx server instance
server {
listen 80;
server_name yourdomain.com yourdomain;
access_log /var/log/nginx/yourdomain.log;

# pass the request to the node.js server with the correct headers
# and much more can be added, see nginx config options
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://app_yourdomain/;
proxy_redirect off;
}
}

如果你想Nginx(>=1.3.13) 同时能处理 websocket 请求, 在 location / 部分添加以下几行:

1
2
3
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

配置好以后, 如果想启用这些配置,软连接至 /usr/local/etc/nginx/sites-enabled :

1
2
3
$ cd /usr/local/etc/nginx/sites-enabled/
$ ln -s /usr/local/etc/nginx/sites-available/default default
$ ln -s /usr/local/etc/nginx/sites-available/express express

然后重启 php-fpm 使配置生效。然后就可以通过 http://yourdomain.com 来访问 Express 程序,记得需要修改 hosts 文件, 将yourdomain.com 指向127.0.0.1 。

5. 安装MySQL

依旧是很简单:

1
$ brew install mysql

启动MySQL:

1
2
3
4
5
6
7
# 启动和关闭
mysql.server start
mysql.server stop

# 开机启动
ln -sfv /usr/local/opt/mysql/\*.plist /Library/LaunchAgents
launchctl load /Library/LaunchAgents/homebrew.mxcl.mysql.plist

启动后默认应为空密码,可以通过mysqladmin设置一个密码

1
$ mysqladmin -uroot password "yourpassword"

6. 安装Memcached

1
brew install memcached

启动/停止指令

1
2
3
4
5
memcached -d
killall memcached

# 加入开机启动
cp /usr/local/Cellar/memcached/1.4.20/homebrew.mxcl.memcached.plist /Library/LaunchAgents/

7. 配置Alias

1
2
3
4
5
6
7
8
9
10
11
12
alias nginx.start='launchctl load -w /Library/LaunchAgents/homebrew.mxcl.nginx.plist'
alias nginx.stop='launchctl unload -w /Library/LaunchAgents/homebrew.mxcl.nginx.plist'
alias nginx.restart='nginx.stop && nginx.start'
alias php-fpm.start="launchctl load -w /Library/LaunchAgents/homebrew.mxcl.php56.plist"
alias php-fpm.stop="launchctl unload -w /Library/LaunchAgents/homebrew.mxcl.php56.plist"
alias php-fpm.restart='php-fpm.stop && php-fpm.start'
alias mysql.start="launchctl load -w /Library/LaunchAgents/homebrew.mxcl.mysql.plist"
alias mysql.stop="launchctl unload -w /Library/LaunchAgents/homebrew.mxcl.mysql.plist"
alias mysql.restart='mysql.stop && mysql.start'
alias memcached.start="launchctl load -w /Library/LaunchAgents/homebrew.mxcl.memcached.plist"
alias memcached.stop="launchctl unload -w /Library/LaunchAgents/homebrew.mxcl.memcached.plist"
alias memcached.restart='memcached.stop && memcached.start'

文章参考

  1. Mac下安装LNMP(Nginx+PHP5.6)环境
  2. 全新安装Mac OSX 开发者环境
  3. NodeJS-Nginx StackOverflow

产品狗刚入门时的容易犯错的小事

测试要点

  1. 登录注册功能,要加强力度测,测试非法注册,高频登录
  2. 网页的 Favicontitlekeywordsdescription
  3. 所有图片和链接的alttitile
  4. 输入框在没有输入和输入非法字符的测试
  5. 所有链接的正确性,保证跳转到正确的页面
  6. 设计到js组件的测试要考虑极限情况,比如轮播图最开始和最尾的事件响应

产品要点

  1. 需求给的活动要进行确认,确认有没有开启
  2. 设计中二态,对齐,线条颜色,字体大小和颜色,图片效果都要确认
  3. 如果一项功能要程序进行开发。那么在设计原型的时候就要跟技术确认好
  4. 交互说明一定要详细,链接到什么位置,每个按钮是怎么出现的,hover前和hover后
  5. 尽快确定一个测试版本。然后上线后统一回报错误。不要一直不上线,一直在测试改进
  6. 设计稿的位置一定要准确,不要以为程序会自动调整。任何一点都要仔细
  7. 设计的效果脑子要有一个大概,跟设计说的时候,验收的时候都会有用
  8. 制作之前开会!!!把所有细节的按钮和交互,链接都要说清楚。并以文档形式交付
  9. 登录状态下的情况,未登录状态下的情况
  10. 游戏顺序全部都需要找运营来定

生活总是莫名其妙

生活真是各种起承转折,懒懒散散准备好入职资料,洗掉脏衣服迎接新工作的时候,被电话告知“您明天不用来了”。

脑子一瞬间放空,然后本能的不失逼格的回一句“明白,再见”。

这生活的幽默把我玩大了,来电时间是下午1:31,而我在1点的时候放弃了原本2:00的一个面试。

挂掉电话,喊不出来,只感觉压抑,一股绝望般的情绪夹杂着疲倦将我击蒙。感觉房间里忽然很灰暗,越是在黑暗中,越有对光的渴望。

我不能就这么放弃,拿好简历穿上衣服打的去。出租车上阳光这么好,风这么舒服,司机虽然走了远路,我想即使面试不成功,也当是散心了。

还好他们没有因为时间原因责备我,做完测试题,和平台经理的面试过程让我感觉一切都是天意。

这位平台经理让我深深的感受到自己的不足,从对用户体验的研究,到项目管理方式,最重要的是指出我思维的误区。他让我知道做产品不能太用自己的想法,一个需求,我还没问清楚就开始设计,设计的是漏洞百出的。他问我看过了哪些书,我忽然感觉自己也没怎么看过几本书,看过也没有应用到自己的生活工作中。 他说他也做了很长时间的研发,才转的产品,他曾经两天看完两本书,一晚上看完Axure英文文档附加制作原型。我顿时感觉我失业的这么多天,每天都迷茫过多,学习太少。看一本书还磨磨蹭蹭好长时间看不完。回来的路上,看到一篇微博,写着为理想奋斗吃的那些苦,感觉自己理想上有冲劲,但行动上从来没跟上。

多谢这位经理,他真的是让我豁然开朗,我应该要学什么,怎么学清晰了然。

我再次感谢生活给我的这些转折,如果我没有失去那份工作,我便不会遇见这位经理,也就不会如此明白自己不足,也不会明白什么叫做刻苦。

晚上小区停电了,世界无聊了许多。然后妈妈打电话过来了,还没接起来,我就感觉一阵阵的心酸。我骗她说我已经上班了,她还不知道我唯一拿到的offer还被我丢掉了。我还是决定谎言来保护最爱的人。他问我工作怎么样,同事怎么样,我装作若无其事的回答着她。她说我爸老了,不想种地了,说啥时候我有孩子了,他们就不种地照顾孩子,我不知所措。我只有努力。拼尽全力。

五月一我决定回家了。

等风来

一向文采翩翩的我好久不写东西,居然不知道从何说起

将《等风来》看了两遍,感觉自己很像程羽蒙,自诩不凡,想一直跑着冲着就能飞起来。

跑了好久,到不知道为什么跑的这么急,这么慌,怕跑慢了我就老了,就没法趁年轻疯狂了。

装着理想,还要看着房价,当自己疯着狂着度过这一年的时候,银行卡的数字总是很孤单。

知乎上看到一个问题,你什么时候感觉自己很穷。

前两天回烟台宿舍小party的时候有件小事忽然让我感觉自己很穷。

我问好基友B哥,买房基金攒多少了。 我感觉这应该和我差不多吧,1w OR 2w ?

他说,6w。

我感觉很神奇。。看看给老妈的那张银行卡孤零零的一万,想想自己领着他1.5倍的工资,忽然感觉自己很穷。

他说我生活丰富啊,演唱会都去过两场了。 我也这么安慰自己,但是忽然有了现实的压力。

话说又相亲去了,恩。。果不出所料,90后在相亲活动中是没有任何市场的。80后的姐姐们带着和弟弟聊聊家常的心态在和我们“相亲”

但是!

我当天华日朗朗乾坤当众对着一姑娘说我很中意你啊。多谢那几瓶鸡尾酒。

我喜欢她? 别开玩笑了。 她是极好的,但是买菜都不能看一眼就带走,何况喜欢一个人。

我只是想如果今晚不做点BlingBling的事情,是多么无趣,同时锻炼下自己的胆子啊!

她确实是我中意的那类型。 但是像两个世界的人。

我看她在旁边蹦蹦跳跳,领着小朋友玩,我就知道她跟我是一路人,应该会对味。

但是又能如何呢? 我一直认为,女朋友是吸引来的,追只不过是吸引到她的一种方法。

如果你没有吸引她的地方,你用尽千方百计追来追去也不过枉然。

一边说着我爱你,一边不思进取打游戏,这样谁能看到未来。

改变自己,变的优秀,时机到了,自然而然。

我会一步一步变优秀,然后走到未来的你面前。

Git reset和revert的区别

两者的说明

  • git reset 重置
  • git revert 撤销

从字面上理解,重置是不管你做了多少次commit,一次性就撤回去了。

撤销的话,只能撤销某一次的commit

譬如,

commit-1, commit-2, commit-3, commit-4

运行 git reset --HARD HEAD~2

重置到倒数第三个状态 ,那么还剩

commit-1, commit-2

运行 git revert HEAD~2

撤销倒数第二个状态, ,就是删除 commit-2,那么还剩

commit-1,commit-3,commit-4

Git reset 的参数 –soft –mixed –hard

先这么理解一下,比较好懂

  1. git reset -soft : 取消了commit

  2. git reset -mixed(默认) : 取消了commit ,取消了add

  3. git reset -hard : 取消了commit ,取消了add,取消源文件修改

git reset head~1,这个相当于带了--mixed参数, 这样已经修改的文件内容不会变,只不过commit信息没 了,需要重新进行add 然后再commit

git reset --soft HEAD~1, 这个相当于git reset --mixed 以后,又加上了 git add ,文件内容不会变,但是改动都放在了待提交区里面。 所以就可以用 git reset --soft [ID]来合并几次commit信息。

git reset --hard HEAD~1,不仅重置了commit信息,文件中已经修改的部分也会丢失。譬如想放弃所有更改干干净净回到某一个版本,就可以 git reset --hard HEAD

Socket.io握手和验证流程

Socket.io 支持两种方式的认证:

  1. 在初始化或者对话握手的时候进行全局的验证。
  2. 每个namespace下进行独立认证。

全局认证和namespace层的独立认证可以同时使用或者单独使用其中某一个。他们唯一的共同点是通用 handshakeData这个对象。 这个数据通过握手时发送的数据生成。所以如果想更好的了解怎么使用认证,首先要先理解握手过程。

握手

当客户端想和Socket.io服务器建立一个稳定的实时连接的时候,需要首先进行握手过程。握手过程通过一个XHR请求或者JSONP(跨域请求)请求进行初始化。

服务器收到连接请求时便会收集请求数据以便后来可能使用。这么做有两个原因:

  1. 用户可能想根据客户端的头信息(headers)或者IP地址进行认证。
  2. 不是所有的传输协议在与服务器建力实时连接的时候会发送头信息,所以我们内部的将握手信息存起来,确保用户在连接建立以后还可以使用这些数据。比如:你可能想在cookie headers里面读取session id,或者为一个连接初始化Express session

handshakeData对象包含以下信息:

1
2
3
4
5
6
7
8
9
10
{
headers: req.headers, // <Object> 请求的头信息
time: (new Date) +'', // <String> 连接的时间信息
address: socket.address(), // <Object> 远程的IP和端口对象
xdomain: !!headers.origin, // <Boolean> 是否是跨域请求
secure: socket.secure, // <Boolean> 是否是https加密协议
issued: +date, // <Number> 连接建立时的时间戳
url: request.url, // <String> 请求入口地址
query: data.query // <Object> URL参数对象(url.parse().query 的结果)或者空对象
}

address对象请参照 socket.address()

在获取所有信息之后,我们检查全局认证方法是否配置好了。如果是全局认证方法那么我们将 handshakeData对象和一个回调函数当参数传进去。调用回调函数时,我们将handshakeData保存起来,这样在connection事件里面就可以通过socket.handshake属性访问到了。根据毁掉函数的返回值,我们就可以返回403.500错误或者200成功响应。

全局认证

可以通过设置authorization函数开启全局认证。

1
2
3
4
5
io.configure(function (){
io.set('authorization', function (handshakeData, callback) {
callback(null, true); // error first callback style
});
});

上面的认证函数里面会受到两个参数:

  1. 在握手过程中生成的handshakeData对象
  2. 回调函数(告诉socket.io是否验证成功);鉴于握手时有可能要查询数据库,所以回调函数来传回结果。 回调函数包含两个参数,error参数可以是未定义的null,也可以是一个字符串提示。authorizedboolean类型的,用来标识客户端是否通过验证。

发送错误或者设置authorized同样可以不允许客服端连接上服务器。

因为handshakeData 是在认证后才保存的,所以你可以编辑添加删除这个对象的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var io = require('socket.io').listen(80);

io.configure(function (){
io.set('authorization', function (handshakeData, callback) {
// findDatabyip is an async example function
findDatabyIP(handshakeData.address.address, function (err, data) {
if (err) return callback(err);

if (data.authorized) {
handshakeData.foo = 'bar';
for(var prop in data) handshakeData[prop] = data[prop];
callback(null, true);
} else {
callback(null, false);
}
})
});
});

小小的提示一下:因为全局认证和namespace认证共享一个handshakeData对象,所以当你在全局认证的时候删除了头信息(headers)或者其他重要的信息以后,在namespace认证的时候就访问不到啦。同样的,在全局认证时添加的所有数据都可以在局部认证时访问到。

不仅在namespace下可以访问handshakeData对象,socket连接也可以读写handshakeData对象。所以在handshakeData里面存的数据,在namespace下的connection事件里都可以通过socket.handshake属性访问到。如下面代码所示:

1
2
3
4
io.sockets.on('connection', function (socket) {
console.log(socket.handshake.foo == true); // writes `true`
console.log(socket.handshake.address.address); // writes 127.0.0.1
});

客户端怎么处理全局认证

认证失败的时候,客户端这边可以监听该socket链接的error事件。同样可以监听namespace下的error事件,但是这样这里会有更多来自namespace下其他有关的错误,而不是来自无法链接产生的错误。

对于成功的链接,只要监听connect事件就好了。

例子:

1
2
3
4
5
6
7
8
9
var sio = io.connect();

sio.socket.on('error', function (reason){
console.error('Unable to connect Socket.IO', reason);
});

sio.on('connect', function (){
console.info('successfully established a working connection \o/');
});

Namespace (命名空间)下的局部认证

可以根据namespace进行不同的认证,这样可以更灵活的认证。比如你可能有一个namespace用来公共聊天,然后对于注册的用户提供额外的聊天服务。

所有的命名空间都可以进行验证。通过链式的方法对一个命名空间注册验证方法。这个验证方法的参数和全局验证的一样一样的。

1
2
3
4
5
6
7
8
9
var io = require('socket.io').listen(80);

io.of('/private').authorization(function (handshakeData, callback) {
console.dir(handshakeData);
handshakeData.foo = 'baz';
callback(null, true);
}).on('connection', function (socket) {
console.dir(socket.handshake.foo);
});

客户端怎么处理局部认证

局部验证失败的处理稍微和全局认证的处理有点不同。验证失败时我们不再发送error事件,二是发送connect_failed事件。当然,验证成功后和你想的一样,会发射connect事件。

例子:

1
2
3
4
5
6
7
8
9
10
var sio = io.connect()
, socket = sio.socket;

socket.of('/example')
.on('connect_failed', function (reason) {
console.error('unable to connect to namespace', reason);
})
.on('connect', function () {
console.info('sucessfully established a connection with the namespace');
});

蛋疼时候的碎碎念

我不愿让你一个人,从大三唱到如今毕业一年。也始终未曾遇到那位和我一起去听五月天演唱会的人。我听五月天,也听E神。E神1874里唱 “仍然没有遇到那位和我绝配的恋人 你根本也没有出现,还是已然逝去”像是最能说明的吧。

正因为五月天,所以我不想让青春如此荒凉谢幕。 我从不怕爱错就怕没爱过。
如果没有一个人一起去听过五月天,青春是少了多鲜艳的一抹亮色。

盛夏正要一天一天的过完,6.11石家庄听完,8月17也马上过去。听过这场,如果再不曾遇到那么一位,我便不会再去演唱会了把。人生啊,总有些事儿是不能完美,总有些事留在那里成为遗憾。

理想中的她应该是个吃货,懂得吃才会生活。 听五月天E神爱吃辣~ 哈哈
别看上面写的那么文绉绉,我真不是文艺青年。。范儿青年才是真身。所以。。她也不能是文艺青年,不然讲个冷笑话她都能当成古诗文 = = ! 而且自古文艺青年忧伤多。。我喜欢笑起来没心没肺还能保持八颗牙齿的 哈哈~

===== 仅以此文纪念我那点无处释放的寂寞悲伤把 =====

Git协作流程规范

平时在使用Git时候,如果有冲突,就需要一次合并提交, 导致整个git 主线很乱,而且经常的合并比较容易出现问题。 这样是 non fast-forward 合并。

可以看下这边文章,这篇文章是我们现在用的方法:

解决合并的冲突 - non fast-forward合并

我们要改为用 rebase 进行合并, 这样就可以是 fast-forward 合并了,请查看这边文章

rebase 合并的冲突 - fast-forward合并

具体的流程如下

1.去自己的工作分支

1
$ git checkout work

然后开始工作,开发功能修复BUG
….

2.提交工作分支的修改

1
$ git commit -a

3.回到主分支

1
$ git checkout dev

4.获取远程最新的修改,此时不会产生冲突

1
$ git pull

5.回到工作分支

1
$ git checkout work

6.用rebase合并主干的修改,如果有冲突在此时解决

$ git rebase dev

7.冲突解决完毕后

1
$ git rebase --continue

8.回到主分支

1
$ git checkout dev

9.合并工作分支的修改,此时不会产生冲突。

1
$ git merge work

10.提交到远程主干

1
$ git push

这样做的好处是,远程主干上的历史永远是线性的。每个人在本地分支解决冲突,不会在主干上产生冲突。