Gowhich

Durban's Blog

为了防止未定义的变量,导致程序运行失败,需要我们判断下变量是否未undefined

1
typeof(decryptData) != "undefined" ? decryptData.payResult : ''

这里还是个对象的值,想想如果不是undefined,但是没有payResult的情况吧。

本人喜欢啤酒,特别喜欢北方啤酒,而且是我家乡的啤酒,嘿嘿。

在南方几年了,还是一直不太喜欢苦涩的啤酒味道。

最近了解了下黄啤酒黑啤酒的喝法,哈哈,嘴馋,嘴真馋。不说了下面见分享吧。

搭配术一:珊帝

材料准备:

七喜饮料一罐

黄啤酒一瓶

冰块一杯

开始搭配:

找一个很大的杯子,具体多大看你自己了,倒入一个半罐七喜,倒入等量的黄啤酒,好了,加入适量的冰块。稍等片刻就可以享受了。

搭配术二:黑色丝绒

材料准备:

方糖【这个超市有卖,如果对咖啡有研究,应该也不会缺少这个的】

一罐苏打水【应该也有瓶装的】

一瓶黑啤酒

一瓶起泡酒

开始搭配:

找个很大的杯子,倒入方糖,找个器材捣碎,然后倒入苏打水,置入冰块,倒入适量黑啤酒,倒入适量起泡酒。可以去happy了。

搭配术三:绿芽冰啤

材料准备:

绿茶茶叶

热水

绿茶饮料

冰块

一瓶黄啤酒

柠檬一片

开始搭配:

找个很大的杯子,放入绿茶叶,热水,防止片刻,倒入绿茶饮料,放入冰块,倒入适量黄啤酒,在放入柠檬一片。happy time!

搭配术四:雪顶黑皮

材料准备:

一瓶黑啤酒

巧克力冰淇淋

开始搭配:

找个很大的杯子,倒入黑啤酒,放入巧克力冰淇淋。happy happy time!

搭配术五:可口波打

材料准备:

一罐可乐

冰块

一瓶黑啤酒

开始搭配:

找一个很大的杯子,倒入适量可乐,放入冰块,倒入适量黑啤酒。很简单吧。happy time go!

这里分享一个node实现的加解密算法,对接了至少三家的接口但是没加的算法都不一样。看着做为程序员的辛苦,我这里分享了。

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* @author zhandapeng <xx@xx>
* @date 7/12/2016
*
* openssl pkcs12 -in 9f_KDJZ_private.pfx -out 9f_KDJZ_private.pem -nodes
* openssl x509 -in 9fwlc_public.crt -outform der -out 9fwlc_public.der
* openssl x509 -in 9fwlc_public.crt -inform der -outform pem -out 9fwlc_public.pem
*
* 玖富加密解密
*/
'use strict';

const crypto = require('crypto');
const constants = require('constants');
const _padding = constants.RSA_PKCS1_PADDING;
const _encoding = 'base64';
const _signatureAlgorithm = 'RSA-SHA1';


class XxxxRSA {
constructor(options) {
this.options = Object.assign({}, options);
}

/**
* 签名
* @param {String} data [加密的数据]
* @return {String} [签名的数据]
*/
_sign(data) {
const sign = crypto.createSign(_signatureAlgorithm);
sign.update(data, 'utf8');
return sign.sign(this.options.privateKey, _encoding);
}

/**
* 验签
* @param {String} sign [签名数据]
* @param {String} data [加密数据]
* @return {Boolean} [description]
*/
_verify(sign, data) {
const verifier = crypto.createVerify(_signatureAlgorithm);
verifier.update(new Buffer(data, _encoding), 'utf8');
return verifier.verify(this.options.publicKey, new Buffer(sign, _encoding));
}

/**
* 加密
* @param {String} msg [要加密的数据]
* @return {Object} [签名的数据和加密的数据]
*/
encrypt(msg) {
const blockSize = 128;
const padding = 11;

let buffer = new Buffer(msg);

const chunkSize = blockSize - padding;
const nbBlocks = Math.ceil(buffer.length / (chunkSize));

let outputBuffer = new Buffer(nbBlocks * blockSize);
for (let i = 0; i < nbBlocks; i++) {
let currentBlock = buffer.slice(chunkSize * i, chunkSize * (i + 1));
let encryptedChunk = crypto.publicEncrypt({
key: this.options.publicKey,
padding: _padding
}, currentBlock);

encryptedChunk.copy(outputBuffer, i * blockSize);
}

return {
data: outputBuffer.toString(_encoding),
sign: this._sign(outputBuffer)
};
};

/**
* 解密
* @param {Object} obj [签名数据和加密数据]
* @return {String} [解密的数据]
*/
decrypt(obj) {
if (!this._verify(obj.sign, obj.data)) {
throw new Error('Sign verify field.');
}

const blockSize = 128;
let buffer = new Buffer(obj.data, _encoding);
const nbBlocks = Math.ceil(buffer.length / (blockSize));
let outputBuffer = new Buffer(nbBlocks * blockSize);

let totalLength = 0;
for (var i = 0; i < nbBlocks; i++) {
let currentBlock = buffer.slice(blockSize * i, Math.min(blockSize * (i + 1), buffer.length));
let decryptedBuf = crypto.privateDecrypt({
key: this.options.privateKey,
padding: _padding
}, currentBlock);

decryptedBuf.copy(outputBuffer, totalLength);
totalLength += decryptedBuf.length;
}

let data = outputBuffer.slice(0, totalLength);

return data.toString();
};
}

export default XxxxRSA;

事实上简单的不得了,只是我不会而已,对不起献丑了。

这里针对java和php版本做个参考。主要是是说encrypt和decrypt部分。

encrypt->java实现

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
public static String encrypt(Key key, String dataStr)
throws RuntimeException {
try {
byte[] data = dataStr.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.ENCRYPT_MODE, key);

int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
int leavedSize = data.length % MAX_ENCRYPT_BLOCK;
int blocksSize = leavedSize != 0 ? data.length / MAX_ENCRYPT_BLOCK
+ 1 : data.length / MAX_ENCRYPT_BLOCK;
byte[] raw = new byte[outputSize * blocksSize];
int i = 0;
while (data.length - i * MAX_ENCRYPT_BLOCK > 0) {
if (data.length - i * MAX_ENCRYPT_BLOCK > MAX_ENCRYPT_BLOCK)
cipher.doFinal(data, i * MAX_ENCRYPT_BLOCK,
MAX_ENCRYPT_BLOCK, raw, i * outputSize);
else
cipher.doFinal(data, i * MAX_ENCRYPT_BLOCK, data.length - i
* MAX_ENCRYPT_BLOCK, raw, i * outputSize);
i++;
}
return Base64.encodeBase64String(raw);

} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (ShortBufferException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

decrypt->java实现

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
public static String decrypt(Key key, String dataStr)
throws RuntimeException {
try {
byte[] data = Base64.decodeBase64(dataStr);
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE, key);
ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
int j = 0;

while (data.length - j * MAX_DECRYPT_BLOCK > 0) {
bout.write(cipher.doFinal(data, j * MAX_DECRYPT_BLOCK,
MAX_DECRYPT_BLOCK));
j++;
}
return new String(bout.toByteArray(), "UTF-8");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

encrypt->php实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public function encrypt($content, $public_key) {
$priKey = file_get_contents($public_key);
$res = openssl_get_publickey($priKey);
//把需要加密的内容,按128位拆开加密
$result = '';
for($i = 0; $i < ((strlen($content) - strlen($content)%117)/117+1); $i++ ) {
$data = mb_strcut($content, $i*117, 117, 'utf-8');
openssl_public_encrypt($data, $encrypted, $res);
$result .= $encrypted;
}
openssl_free_key($res);
//用base64将二进制编码
$result = base64_encode($result);
return $result;
}

decrypt->php实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function rsaDecrypt($content, $private_key) {
$priKey = file_get_contents($private_key);
$res = openssl_get_privatekey($priKey);
// var_dump($priKey);
// var_dump($res);exit();
//用base64将内容还原成二进制
$content = base64_decode($content);
//把需要解密的内容,按128位拆开解密
$result = '';
for($i = 0; $i < strlen($content)/128; $i++ ) {
$data = substr($content, $i * 128, 128);
openssl_private_decrypt($data, $decrypt, $res);
$result .= $decrypt;
}
openssl_free_key($res);
return $result;
}

nodejs中,在做加密解密的时候,会得到第三方的各种各样的加密文件,其后缀也就那么几种吧,.key/.pem/.pfx等,是不是可以自定义,反正就是一个文件。

但是今天我看了很多的nodejs库好像也没有找到与java keytool这样的工具,因为在java里面,完全是可以读取pfx,然户进行在进行处理的,如果在nodejs中要如何操作,目前不知道,使用openssl做个转换处理先。

第一个命令是:

1
openssl pkcs12 -in xxxx.pfx -nocerts -nodes -out domain_encrypted.key

第二个命令是:

1
openssl rsa -in domain_encrypted.key -out private.key

哪位大神知道的,可以告知下,谢谢了。

==================补充=================

google上有个办法可以解析出两种格式的文件

第一种格式文件的方式

extract private key from .pfx file

1
2
3
# openssl pkcs12 -in myfile.pfx -nocerts -out private_key.pem -nodes
Enter Import Password:
MAC verified OK

第二种格式文件的方式

extract certificate from .pfx file

1
2
3
# openssl pkcs12 -in myfile.pfx -nokeys -out certificate_file.crt 
Enter Import Password:
MAC verified OK

详细的可到这里:http://tecadmin.net/extract-private-key-and-certificate-files-from-pfx-file/

==========================================

==========================================强烈补充

多日奋战,终于解决了这个问题,因为一直是一个私钥解密的问题

1
2
openssl pkcs12 -in xxxx_private.pfx -out xxxx_private.pem -nodes
openssl x509 -in xxxx_public.crt -inform der -outform pem -out xxxx_public.pem

这里主要是针对具体情况具体描述,可以变通取处理

因为对方给过来的是一个在window环境下,使用工具生成的pfx和crt文件。

经过对方给过来的生成工具的描述,这个crt文件还是一个cer后缀文件自己修改的cer->crt。可见这里如果对文件内容不了解,光从后缀来看会坑了很多人。

先来看第一行的命令语句.

经过文档的查询pfx文件是一个带有私钥跟证书的合体文件,通过上面的命令就可以得到一个文件就是private.pem,里面是一个含有证书和私钥的。

不知道的我这里举例。

私钥是以

1
-----BEGIN RSA PRIVATE KEY-----

开头的。

证书是以

1
-----BEGIN CERTIFICATE-----

开头的。对不起不方便把所有内容同时贴出来。很容易辨别的。

然后对方还会给你一个crt文件,这个事实上就是一个x509对应的证书,需要解出来,但是对于是java的应该就不需要了,不过是php的或这是node的就需要了。

当然是证书的话,就必须是以

1
-----BEGIN CERTIFICATE-----

开头的。

好了,如果你跟别人对接接口,遇到私钥公钥的问题,但是对方给了你pfx和crt文件的话,就按照这个命令去操作的吧,我已经在php和node环境下试过了。不过具体的算法还是要针对具体的情况来实施。

================2016-11-11补充================

1
2
3
4
5
6
7
REM export the ssl cert (normal cases)
openssl pkcs12 -in aa.pfx -out aa.pem -nokeys -clcerts

REM export the ssl cert (Crescendo load balancers)

openssl pkcs12 -in aa.pfx -out aa_tmp_cn.pem -nodes
openssl x509 -in aa_tmp_cn.pem -out aa_cn.pem -text

bootstrap下面有个glyphicon-refresh,但是不会自定动态spin[旋转],下面提供下我的实例

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
.spin{
-webkit-transform-origin: 50% 50%;
transform-origin:50% 50%;
-ms-transform-origin:50% 50%; /* IE 9 */
-webkit-animation: spin .8s infinite linear;
-moz-animation: spin .8s infinite linear;
-o-animation: spin .8s infinite linear;
animation: spin .8s infinite linear;
}

@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}

调用方式如下

1
<span class="glyphicon glyphicon-refresh loading spin"> </span>

最近做redis的集群配置,想到一个问题,就是配置文件要是我能用命令替换就好了,就不需要每次打开文件去编辑一遍。

于是让我发现了sed这个命令,那么今天就记录下如何来替换文件里面的内容。起始就是学习了,记得下次使用就好了。

首先新建目录

test

新建两个文件

test/a.txt

test/b.txt

1
ll test

结果如下

1
2
-rw-r--r--  1 durban126  staff    22B  7  9 00:42 a.txt
-rw-r--r-- 1 durban126 staff 15B 7 9 00:25 b.txt

a.text的内容是

wo wo gowhich gowhich

b.text的内容是

eo eo gowhich gowhich

然后我们通过sed命令来做文件内容替换,将wo替换位eo

Mac OS 环境

1
2
sed -ig "s/wo/eo/g" `grep wo -rl ./test`
sed -i "" "s/wo/eo/g" `grep wo -rl ./test`

1
sed -i ".bak" "s/wo/eo/g" `grep wo -rl ./test`

Linux 环境

1
sed -i "s/wo/eo/g" `grep wo -rl ./test`

之所以不同,是因为Mac OS下要求强制备份。

我们先执行

1
sed -ig "s/wo/eo/g" `grep wo -rl ./test`

结果是:

1
2
3
-rw-r--r--  1 durban126  staff    22B  7  9 00:55 a.txt
-rw-r--r-- 1 durban126 staff 22B 7 9 00:42 a.txtg
-rw-r--r-- 1 durban126 staff 15B 7 9 00:25 b.txt

a.txt的内容是

1
2
3
4
5
╭─xxxx@xxxx ~/php ‹ruby-2.2.1› 
╰─➤ cat test/a.txt
eo eo gowhich gowhich
╭─xxxx@xxxx ~/php ‹ruby-2.2.1›
╰─➤

但是a.txtg就不是了,已做了备份处理

1
2
3
4
5
╭─xxxx@xxxx ~/php ‹ruby-2.2.1› 
╰─➤ cat test/a.txtg
wo wo gowhich gowhich
╭─xxxx@xxxx ~/php ‹ruby-2.2.1›
╰─➤

再来看看执行

1
sed -i "" "s/wo/eo/g" `grep wo -rl ./test`

结果是

1
2
3
4
5
╭─xxxx@xxxx ~/php ‹ruby-2.2.1› 
╰─➤ ll test
total 16
-rw-r--r-- 1 durban126 staff 22B 7 9 01:06 a.txt
-rw-r--r-- 1 durban126 staff 21B 7 9 00:58 b.txt

a.txt的内容也变化了。

1
2
3
╭─xxxx@xxxx ~/php ‹ruby-2.2.1› 
╰─➤ cat test/a.txt
eo eo gowhich gowhich

但是没有了备份文件了。

1
sed -i ".bak" "s/wo/eo/g" `grep wo -rl ./test`

这个命令就会跟

1
sed -ig "s/wo/eo/g" `grep wo -rl ./test`

类似了,做了文件备份喽

1
2
3
4
5
6
╭─xxxx@xxxx ~/php ‹ruby-2.2.1› 
╰─➤ ll test
total 24
-rw-r--r-- 1 durban126 staff 22B 7 9 01:09 a.txt
-rw-r--r-- 1 durban126 staff 22B 7 9 01:09 a.txt.bak
-rw-r--r-- 1 durban126 staff 21B 7 9 00:58 b.txt

a.txt.bak的内容就是备份a.txt的内容了。

还有另外一个命令

1
sed -i "s/wo/eo/g" `grep wo -rl ./test`

结果是会报错了,

1
2
3
╭─xxxx@xxxx ~/php ‹ruby-2.2.1› 
╰─➤ sed -i "s/wo/eo/g" `grep wo -rl ./test`
sed: 1: "./test/a.txt.bak": invalid command code .

所以还是区分下环境比较好。

但是命令

1
sed -ig "s/wo/eo/g" `grep wo -rl ./test`

是在另种情况下通用的。

PS:

-i 表示inplace edit,就地修改文件
-r 表示搜索子目录
-l 表示输出匹配的文件名

最近项目需要,需要在服务器上做下redis的集群配置。

这里说下我自己的经验,应该是redis自3版本以后才支持redis,以前的版本也有集群,但是不是真正意义上的集群,从配置文件上就能够分别出来,3以前的版本是没有cluster的相关配置项的,从3版本以后才开始支持的。这个导致我一直以为3以前的版本也是支持的,折腾了好久,不过2版本可以通过master/slave的方式搭建类似集群的功能。

所以,如果你是想使用redis的集群功能,首先还是把自己的redis升级为至少是3版本的吧。

我这里记录的是redis 3.2.1版本的。

整个的配置流程事实上是可以直接使用redis自己提供的create-cluster进行创建,这个工具整个进行管理起来比较方便快捷,就是在配置上都不够便捷。

首先就是下载redis,下载地址:http://download.redis.io/releases/redis-3.2.1.tar.gz

下载后解压到目录/usr/local/redis目录【这里不熟悉tar 命令的自行google】

进入到redis目录后执行

1
make

如果需要root权限的话,执行

1
sudo make

我这里因为有人已经在系统里面安装了redis,我有不想去打扰他的,我就自己干一个独立的好了,事实上也是互不干扰的。

如果是独立安装的话,可以接着执行

1
make install

1
sudo make install

如果跟我一样的话,上面的环节就可以省略了。

接下来,我按照我的情况来说。

进入到src目录下面,应该会有很多你熟悉的命令文件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
╭─zhangdapeng@qeeniao4-HZ /usr/local/redis/src  
╰─➤ ls
adlist.c bio.h db.c intset.c multi.c rand.h redis-cli.o sds.o sparkline.c util.h
adlist.h bio.o db.o intset.h multi.o rand.o redis-sentinel sentinel.c sparkline.h util.o
adlist.o bitops.c debug.c intset.o networking.c rdb.c redis-server sentinel.o sparkline.o valgrind.sup
ae.c bitops.o debug.o latency.c networking.o rdb.h redis-trib.rb server.c syncio.c version.h
ae_epoll.c blocked.c dict.c latency.h notify.c rdb.o release.c server.h syncio.o ziplist.c
ae_evport.c blocked.o dict.h latency.o notify.o redisassert.h release.h server.o testhelp.h ziplist.h
ae.h cluster.c dict.o lzf_c.c object.c redis-benchmark release.o setproctitle.c t_hash.c ziplist.o
ae_kqueue.c cluster.h endianconv.c lzf_c.o object.o redis-benchmark.c replication.c setproctitle.o t_hash.o zipmap.c
ae.o cluster.o endianconv.h lzf_d.c pqsort.c redis-benchmark.o replication.o sha1.c t_list.c zipmap.h
ae_select.c config.c endianconv.o lzf_d.o pqsort.h redis-check-aof rio.c sha1.h t_list.o zipmap.o
anet.c config.h fmacros.h lzf.h pqsort.o redis-check-aof.c rio.h sha1.o t_set.c zmalloc.c
anet.h config.o geo.c lzfP.h pubsub.c redis-check-aof.o rio.o slowlog.c t_set.o zmalloc.h
anet.o crc16.c geo.h Makefile pubsub.o redis-check-rdb scripting.c slowlog.h t_string.c zmalloc.o
aof.c crc16.o geo.o Makefile.dep quicklist.c redis-check-rdb.c scripting.o slowlog.o t_string.o
aof.o crc64.c help.h memtest.c quicklist.h redis-check-rdb.o sdsalloc.h solarisfixes.h t_zset.c
asciilogo.h crc64.h hyperloglog.c memtest.o quicklist.o redis-cli sds.c sort.c t_zset.o
bio.c crc64.o hyperloglog.o mkreleasehdr.sh rand.c redis-cli.c sds.h sort.o util.c

太多了,我们重点关注几个就好了,redis-cli,redis-server,redis-trib.rb.

接下来让我们创建配置文件吧。

进入/usr/local/etc目录,没有的话,就自己建立一个,或者根据自己的情况来也是可以的。

建立一个redis的目录,在redis目录下,从原有的redis.conf复制一份改为redis_7001.conf,由于这里我们需要用到6个,所以我们一次建立了6个redis配置文件

1
2
3
4
5
6
-rw-r--r-- 1 root root 45K 7月   7 18:32 redis_7001.conf
-rw-r--r-- 1 root root 45K 7月 7 18:32 redis_7002.conf
-rw-r--r-- 1 root root 45K 7月 7 18:33 redis_7003.conf
-rw-r--r-- 1 root root 45K 7月 7 18:33 redis_7004.conf
-rw-r--r-- 1 root root 45K 7月 7 18:33 redis_7005.conf
-rw-r--r-- 1 root root 45K 7月 7 18:34 redis_7006.conf

这里我简单的列出需要修改的项

1
2
3
4
5
6
7
8
9
10
bind 114.xxx.xxx.xxx 127.0.0.1//这里是你要绑定的ip地址【这里有料,下面解说】
port 7001//端口号
daemonize yes//
pidfile /var/run/redis_7001.pid
logfile "/var/log/redis/redis_7001.log"
appendonly yes
appendfilename "appendonly.aof"
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 15000

这里只是展示了redis_7001.conf这个文件需要修改的地址,其他5个同样的,只是将7001换成对应的数字就好了。

配置完后,就可以启动喽。

回到redis/src目录,执行

1
2
3
4
5
6
./redis-server /usr/local/etc/redis/redis_7001.conf
./redis-server /usr/local/etc/redis/redis_7002.conf
./redis-server /usr/local/etc/redis/redis_7003.conf
./redis-server /usr/local/etc/redis/redis_7004.conf
./redis-server /usr/local/etc/redis/redis_7005.conf
./redis-server /usr/local/etc/redis/redis_7006.conf

查看是否已经启动了。

ps -ef | grep redis

如果看到如下的结果说明,已经启动成功了,如果有问题,说明还是需要检查一下配置文件。

1
2
3
4
5
6
root     17979     1  0 7月07 ?       00:00:16 ../../../redis/src/redis-server 114.xxx.xxx.xxx:7001 [cluster]
root 17988 1 0 7月07 ? 00:00:16 ../../../redis/src/redis-server 114.xxx.xxx.xxx:7002 [cluster]
root 17997 1 0 7月07 ? 00:00:17 ../../../redis/src/redis-server 114.xxx.xxx.xxx:7003 [cluster]
root 18006 1 0 7月07 ? 00:00:15 ../../../redis/src/redis-server 114.xxx.xxx.xxx:7004 [cluster]
root 18015 1 0 7月07 ? 00:00:16 ../../../redis/src/redis-server 114.xxx.xxx.xxx:7005 [cluster]
root 18024 1 0 7月07 ? 00:00:15 ../../../redis/src/redis-server 114.xxx.xxx.xxx:7006 [cluster]

奇怪了,我这里为啥会显示我自己服务器的ip呢?【就是下面要讲的猛料】

redis是启动成功了,但是我们还要进行一次设置,就是集群的设置,还是在redis/src目录

1
./redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006

命令的意义如下:

  1. 给定 redis-trib.rb 程序的命令是 create , 这表示我们希望创建一个新的集群。
  2. 选项 –replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
  3. 之后跟着的其他参数则是实例的地址列表, 我们希望程序使用这些地址所指示的实例来创建新集群。

简单来说, 以上命令的意思就是让 redis-trib 程序创建一个包含三个主节点和三个从节点的集群。

接着, redis-trib 会打印出一份预想中的配置给你看, 如果你觉得没问题的话, 就可以输入 yes , redis-trib 就会将这份配置应用到集群当中:

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
>>> Creating cluster
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
Adding replica 127.0.0.1:7003 to 127.0.0.1:7000
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
M: 2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
M: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
S: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003
replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2
S: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004
replicates 2d03b862083ee1b1785dba5db2987739cf3a80eb
S: 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005
replicates 0456869a2c2359c3e06e065a09de86df2e3135ac
Can I set the above configuration? (type 'yes' to accept):

输入 yes 并按下回车确认之后, 集群就会将配置应用到各个节点, 并连接起(join)各个节点 —— 也即是, 让各个节点开始互相通讯

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
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join......
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
M: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
M: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003
slots: (0 slots) master
replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2
M: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004
slots: (0 slots) master
replicates 2d03b862083ee1b1785dba5db2987739cf3a80eb
M: 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005
slots: (0 slots) master
replicates 0456869a2c2359c3e06e065a09de86df2e3135ac
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

一切都正常的话会输出

1
2
3
4
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

到这里就一切万事大吉了,如果还是需要其他的额外的帮助,可以到这里看看http://www.cnblogs.com/gomysql/p/4395504.html

【猛料解析】

1
bind 114.xxx.xxx.xxx 127.0.0.1

这里我为哈把地址写成这样呢?主要是是因为,第一个是可以远程了解,换个位置的话也是可以的,但是在远程了解的情况下会出现一个问题,就是在做转向的时候,会由于第一个ip地址的不同而不同,如果是127.0.0.1的话,那么在远程链接的时候就跳转到127.0.0.1这个ip上来了,同理换成其他地址的话,就会跳转到其他地址,自己可以实验一下,可以使用类似node的ioredis的这样库测试,或者直接命令行链接,会比较明显,就是因为这里,如果配置不好的话,后面使用第三方库连接的话,会一直连接不上。

嗯,今晚记录下,由于最近观察google 分析工具发现我网站存在 www.gowhich.com 和 gowhich.com 同时存在的一些问题,建议将其中的一个做301跳转,这个还是超级简单,不过还是记录一下吧,方便记性不好的。

绑定对应的域名当然没有问题了。

1
2
3
4
server {
listen 80;
server_name gowhich.com www.gowhich.com *.gowhich.com ;
}

上面主要展示了主要的部分,后面还是要根据你自己的需要去配置。

1
2
3
4
5
6
7
server {
listen 80;
server_name gowhich.com www.gowhich.com *.gowhich.com ;
if ($host != 'www.gowhich.com') {
rewrite ^/(.*)$ http://www.gowhich.com/$1 permanent;
}
}

或者可以使用等于的判断

1
2
3
4
5
6
7
server {
listen 80;
server_name gowhich.com www.gowhich.com *.gowhich.com ;
if ($host = 'gowhich.com') {
rewrite ^/(.*)$ http://www.gowhich.com/$1 permanent;
}
}

第二个更有针对性吧。

这里有几个问题需要注意一下:

  1. 上述配置文件的if语句与括号必须以一个空格隔开,否则Nginx会报nginx: [emerg] unknown directive “if($host” in…错误。
  2. Nginx的条件判断不等于是!=,等于是=,注意这里的等于只有一个等于号,如果写成==,则Nginx会报nginx: [emerg] unexpected “==” in condition in…错误。
  3. 301永久转向配置成功后,浏览器可能会有记忆效应,比如说IE。所以一旦配置并利用浏览器访问过页面,那么你更改了301转向配置后,这个页面可能依旧是上次的转向,建议清除浏览器缓存,或者尝试访问其他页面,也可以在url的?问号后面加上一些随机的参数,避免浏览器的缓存记忆效应。

配置完成后,可以使用nginx -s reload命令进行平滑的更新配置(不重启Nginx)。

以前使用reactjs做前端开发都是webpack打包然后在运行,这样的好处是,你开发的环境是一个纯碎在写nodejs的感觉,而且还能应用很多ES6的新特性,岂不快哉!

最近在做后端,也由于使用webpack时间长,一直没有找到很好的办法去解决,自动打包缓慢的问题,还有就是每次开发你都要去根据具体情况写要给跟webpack相关的config文件。

于是就试着用Browser的环境进行开发,结果今天尝试下后,果然还是很不错的。

首先引入react,我这里使用reflux,然后再引入reflux,再引入babel。

1
2
3
4
<script src="/js/react.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/js/react-dom.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/js/reflux.min.js" type="text/javascript" charset="utf-8"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.10.3/babel.min.js"></script>

类似下面这样,跟使用jquery是一样的感觉。

接下来我们写一个简单的分页的组件。

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
var Pagination = React.createClass({
clickHandler: function (e) {
e.preventDefault();
if (e.currentTarget.dataset.handle == 'false') {
this.props.listData(e.currentTarget.dataset.page);
}
},
render: function () {
let nextStop = false;
let preStop = false;
if (this.props.currentdata.length < this.props.pagesize) {
nextStop = true;
}

if ((this.props.page - 1) <= 0) {
preStop = true;
}

const preClass = preStop ? 'previous disabled' : 'previous';
const nextClass = nextStop ? 'next disabled' : 'next';

let pre_page = parseInt(this.props.page) - 1;
let next_page = parseInt(this.props.page) + 1;

return (
<nav>
<ul className="pager">
<li className={preClass}>
<a href="#" onClick={this.clickHandler} data-page={pre_page} data-handle={preStop}>
上一页
</a>
</li>
<li className={nextClass}>
<a href="#" onClick={this.clickHandler} data-page={next_page} data-handle={nextStop}>
下一页
</a>
</li>
</ul>
</nav>
);
}
});

Pagination.propTypes = {
currentdata: React.PropTypes.array.isRequired,
page: React.PropTypes.number.isRequired,
pagesize: React.PropTypes.number.isRequired,
listData: React.PropTypes.func.isRequired
};

就是这样,不需要其他的 export的东西,以为我们只要在页面中引入就可以了。

1
<script src='/js/components/partial/Pagination.js' type="text/babel"></script>

就像上面这样就可以了。

下面我们调用一下:

1
2
3
4
5
6
var pagerProps = {
page: this.state.page,
pagesize: this.state.pageSize,
currentdata: this.state.recordItem,
listData: this.loadMorePage
};

这里的loadMorePage是另外组件里面的一个方法,用来加载下一页数据的,page就是页数,pageSize就是每页的数量。

1
2
3
4
5
loadMorePage:function(page){
page = parseInt(page);
this.setState({page: page});
Action.getRecordItem(this.props.uid, page, this.state.pageSize);
},

就像上面这样子,加载一下数据就可以渲染到列表的组件里面去了。然后就是如何再其他组件里面调用了。

1
2
3
<div className="col-md-12">
<Pagination {...pagerProps}/>
</div>

pagerProp就是刚才上面的变量。这样就可以使用了。

总体感觉下来起始跟我之前的使用方法区别就是,不再需要去import和export了。

而且不需要去不断的打包了。不知道后面开发还会遇到啥其他问题,继续更新…

Laravel Blade模版对于我这样的初玩者来说,确实有点挑战。

习惯了,django的直接定义函数就能直接使用的方法,在Blade中还是没有找到如何使用,这里简单介绍下我自己查到的使用方法。

起始Laravel的Blade是支持php的原生写法的,比如我有个输出的变量,是需要进行逻辑判断在输出的。

1
2
3
4
5
6
7
8
<?php $heading = '/images/default.png'; ?>
@if($user->headimg)
@if(strncmp($user->headimg,'http://',strlen('http://')) == 0)
<?php $heading = $user->headimg; ?>
@else
<?php $headimg = "http://7u2r0u.com1.z0.glb.clouddn.com/" . $user->headimg; ?>
@endif
@endif

就这样我就可以实现了定义变量,在使用变量的方便

1
2
3
4
<a href={{ $headimg }} class="fancybox" data-fancybox-type="image">
<img class="img-circle" src={{ $headimg }}
style='width:32px;height:32px'}}/>
</a>
0%