跳到主要内容

node.js 通过 tcp 方式获取随机端口与使用场景

· 阅读需 2 分钟

某些场景可能需要动态的获取端口来启动服务,可能服务化场景,不直接硬配置端口。

哈哈,这看来是要为分布式、服务注册、服务发现做准备呢。

/**
* auto port
* @authors luoyjx (yjk99@qq.com)
* @date 2016-10-16 20:42:57
*/
var net = require('net');

var server = net.createServer();
server.on('error', console.log);
server.on('listening', function () {
var port = server.address().port;

server.close(function () {
console.log('auto port: %s', port);
});
}.bind(this));
// tcp 使用端口 0 表示系统分配端口
server.listen(0);

服务在启动的时候,首先去获取一个可用端口,将自己使用此端口启动,再注册到配置管理中,这样即可实现服务注册了。 配合 etcd 即可实现服务发现,不过还木有实践。

git 命令速查表!

· 阅读需 5 分钟

git add 添加 git commit -m "xxx" 注释提交 git log 提交日志 git log --pretty=oneline 提交日志在一行显示 git reset --hard HEAD~1 回退到上一个提交 git reset --hard 467dcab 回到某个commit git reflog 查看命令历史 git checkout -- file 丢弃工作区修改 git rm 删除一个文件

暂存工作区

git stash 当前工作现场“储藏”起来 git stash pop 恢复并删除stash内容 git stash apply 恢复 git stash drop 删除stash内容 git stash list 列出stash列表

分支管理

git branch 查看分支
git branch `<name>` 创建分支
git checkout `<name>` 切换分支
git checkout -b `<name>` 创建+切换分支
git merge `<name>` 合并某分支到当前分支
git branch -d `<name>` 删除分支
git branch -D name 强行删除分之
git checkout -b dev origin/dev 创建远程分之到本地
git pull 从远程分之拉取
git branch --set-upstream dev origin/dev 指定本地dev分支与远程origin/dev分支的链接

创建分支,修改代码,合并并删除分支过程

git checkout master          切换到主分支
git checkout -b bug-001 创建bug-001分之
git add file 添加文件
git commit -m "fix bug 001" 提交文件并注释
git checkout master 切换到主分支
git merge --no-ff -m "merge bug fix 001" bug-001 bug-001分之合并到当前分支
git branch -d bug-001 删除bug分支

标签管理

git tag 列出标签
git tag v1 打一个新标签
git tag v1 6224937 给某次提交打tag
git tag -a v1 -m "tag desc" 6224937 指定某一标签打tag并注释
git show v1 看到文字说明
git tag -d v1 删除标签
git push origin tagname 推送标签到远程仓库
git push origin --tags 一次推送所有本地未推送标签
git push origin :refs/tags/tagname 删除远程标签

linux 上 openssl 升级

· 阅读需 2 分钟

先查看下自己机器上的 OpenSSL 版本。

openssl version
cd /usr/local/src/
wget http://www.openssl.org/source/openssl-1.0.1g.tar.gz
tar -zxvf openssl-1.0.1g.tar.gz
cd openssl-1.0.1g
./config shared zlib
make && make install

修改历史的OpenSSL文件设置备份

mv /usr/bin/openssl /usr/bin/openssl.old
mv /usr/include/openssl /usr/include/openssl.old

设置软连接使其使用新的OpenSSL版本 刚刚安装的OpenSSL默认安装在/usr/local/ssl

ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/ssl/include/openssl /usr/include/openssl

更新动态链接库数据

echo "/usr/local/ssl/lib" >> /etc/ld.so.conf
ldconfig -v

我们再来看看 OpenSSL 版本信息.

1 2 3

openssl version

OpenSSL 1.0.1g 7 Apr 2014

如果是 1.0.1g,说明你安装正确了

react redux 更新列表中的某个属性时需要注意

· 阅读需 4 分钟

常常会碰到这种需求,对列表中的某个元素进行操作,然后改变这个对象的一个属性值。

今天就在这里踩到了坑。也算是对react渲染机制加深的理解。

是这样的,我有一个好友列表,需要点击添加操作来加好友,而这个用户的对象中有一个属性值是isFriend,再添加成功后需要对其进行改变。

当然,通常的思路就是,把这个列表中的这行记录的那个属性值设为true即可,添加按钮就隐藏掉。 untitled1.png

我在reducer中循环匹配,匹配成功的话就isFriend设置为true,但是呢,奇怪的事情发生了,界面并没有像预想的一样隐藏掉添加按钮。

代码片段如下:

	newArr = oldState.contactsList.map(function mapFunc(contact) {
var result = contact;

if (result.id === action.data) {
result.isFriend = true;
}
return result;
});

return Object.assign({}, oldState, {
contactsList: newArr,
});

看起来确实没有什么不对劲的呀,我打开react-dev-tool看组件的值,也确实改变过来了。什么鬼呢?!

后来找了找,给了我启发,于是动手试了试,果然是因为数组中的对象的引用未改变导致未重新渲染。

修正后的代码如下:

	if (result.id === action.data) {
// 不能直接赋值,此处直接赋值,引用不变,被认为对象为改变,则不重新渲染
result = Object.assign({}, result, {isFriend: true});
}

node.js 实现文件下载

· 阅读需 1 分钟

文件下载实际上是二进制流的发送,所以在服务端是就向客户端写流。

而在node.js中,读流和写流又可以通过pipe连接起来,那么思路清晰之后,就是Content-type类型的问题了。

代码如下

var fs = require('fs');
var pdf = fs.createReadStream(path);

res.writeHead(200, {
'Content-Type': 'application/force-download',
'Content-Disposition': 'attachment; filename=test.rar'
});

pdf.pipe(res);

RE-Build:用自然语言去编写正则表达式

· 阅读需 1 分钟

Build regular expressions with natural language.

由来

你是否遇到过这么复杂的正则表达式呢?

var ipMatch = /(?:(?:1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.){3}(?:1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)\b/;

怎么办

使用re-build

var ipNumber = RE.group(
RE ("1").then.digit.then.digit
.or ("2").then.oneOf.range("0", "4").then.digit
.or ("25").then.oneOf.range("0", "5")
.or .oneOf.range("1", "9").then.digit
.or .digit
),

ipMatch = RE.matching.exactly(3).group( ipNumber.then(".") )
.then(ipNumber).then.wordBoundary.regex;

安装

通过npm : `

npm install re-build

通过bower

bower install re-build

文档

https://github.com/MaxArt2501/re-build

npm 安装 Electron 缓慢网络超时导致失败

· 阅读需 1 分钟
  1. npm源过慢的话,可以把源切到国内的淘宝的镜像上。
npm config set registry https://registry.npm.taobao.org
  1. 到electron的国内镜像下载最新的安装包,主要看好自己系统对应的版本

https://npm.taobao.org/mirrors/electron

  1. 将下载好的包放到当前用户的根目录下的.electron文件夹下,windows一般是C:\Users\YourUserName.electron

  2. 执行安装命令 npm install electron-prebuilt -g

node.js rabbitmq(amqplib) 断线重连

· 阅读需 6 分钟

我用的是amqplib 这个包,github上的项目名是amqp.node

这个包貌似是没有实现断线自动重连的,看了看issues,也和我自己实现的版本差不多。

思路

思路主要是两个地方:

  1. connection实例的error事件.
  2. 初始化的promise链报错.

针对这两种情况都去尝试重新连接,因为可能不能立即恢复,所以得隔一段事件重连一次,直到恢复为止。

封装实现

/**
* Mq Factory
* @authors yanjixiong
* @date 2016-07-22 09:56:19
*/

var Connection = require('./Connection');
var Channel = require('./Channel');
var Exchange = require('./Exchange');
var Queue = require('./Queue');
var Consume = require('./Consume');
var ExchangeTypes = require('../constant').ExchangeTypes;
var RouteKey = require('../constant').RouteKey;

var config = require('../../config');
var log = require('../../common/logger').getLogger('Core:mq:index');

var ROUTE_KEY = RouteKey.RECEIVE_PA;
var QUEUE_NAME = RouteKey.RECEIVE_PA; // 队列名称

function MQ() {
this.connection = null;
this.init();
}

/**
* 初始化消息队列
* @return {[type]} [description]
*/
MQ.prototype.init = function init() {
var self = this;

// 创建连接
Connection
.createConnection(config.rabbitMQ_url)
.then(function (conn) {

// 实例中存储当前连接
self.connection = conn;

// 监听连接错误
conn.on('error', function(err) {
log.error('[mq] connection error ', err);
self.reconnect();
});

log.info('[mq] create connection success');

// 创建通道
return Channel
.createChannel(conn);
})
.then(function (ch) {

// 进程被杀死关闭连接
process.once('SIGINT', function() {
log.info('kill by signal SIGINT');
ch.close();
self.connection.close();
self.connection = null;
process.exit(0);
});

ch.on('error', function(error) {
// ch.close();
log.error('[mq] channel error: ', error);
});

log.info('[mq] create channel success');

// 创建交换机
return Exchange
.assertExchange(ch, config.exchange_name, ExchangeTypes.DIRECT, {durable: false})
.then(function () {
log.info('[mq] assert exchange [%s] [%s]', config.exchange_name, ExchangeTypes.DIRECT);

// 创建队列
return Queue
.assertQueue(ch, QUEUE_NAME, {exclusive: false, durable: false}); // exclusive 是否排它 durable : 是否持久化
})
.then(function (queue) {
log.info('[mq] assert queue [%s] success', QUEUE_NAME);

log.debug(queue);

// 绑定队列到交换机
return Queue.
bindQueue(ch, QUEUE_NAME, config.exchange_name, ROUTE_KEY);
})
.then(function() {
log.info('[mq] bind queue [%s] to exchange [%s]', QUEUE_NAME, config.exchange_name);

// 消费
return Consume
.consume(self.connection, ch, QUEUE_NAME);
})
})
.catch(function (err) {
log.error('[mq] Init failed , error: ', err);
self.reconnect();
});
};

/**
* 重新连接
* @return {[type]} [description]
*/
MQ.prototype.reconnect = function() {
var self = this;

log.info('[mq] try reconnect 3 seconds later');

setTimeout(function () {
self.init();
self.reconnectCount++;
}, 3000);
}

/**
* 获取连接
* @return {[type]} [description]
*/
MQ.prototype.getConnection = function getConnection() {
var self = this;

if (this.connection) {
return Promise.resolve(self.connection);
} else {
return Connection
.createConnection(config.rabbitMQ_url)
.then(function (conn) {
// 实例中存储当前连接
self.connection = conn;

// 进程被杀死关闭连接
process.once('SIGINT', function() {
log.info('kill by signal SIGINT');
conn.close();
self.connection = null;
process.exit(0);
});

log.info('[mq] create connection success');

return Promise.resolve(conn);
});
}
}

module.exports = MQ;

bluebird 的 coroutine 方法 (类似 co )

· 阅读需 1 分钟

可以像co一样包裹generator函数,进行使用yeild的异步操作。

使用

Promise.coroutine(GeneratorFunction(...arguments) generatorFunction) -> function

示例

var Promise = require("bluebird");

function PingPong() {

}

PingPong.prototype.ping = Promise.coroutine(function* (val) {
console.log("Ping?", val)
yield Promise.delay(500)
this.pong(val+1)
});

PingPong.prototype.pong = Promise.coroutine(function* (val) {
console.log("Pong!", val)
yield Promise.delay(500);
this.ping(val+1)
});

var a = new PingPong();
a.ping(0);
Running the example:

$ node test.js
Ping? 0
Pong! 1
Ping? 2
Pong! 3
Ping? 4
Pong! 5
Ping? 6
Pong! 7
Ping? 8
...

node.js 全局安装了却找不到这个命令

· 阅读需 2 分钟

大家都知道,FIS 是要求全局安装的,是因为避免由于 FIS 多版本不同项目目录下而导致编译时有差异,而导致不必要的麻烦。

有些同学可能遇到了

npm install -g fis

命令行执行 fis 说找不到这个命令。这时候一般都开始抓瞎了。

解决办法:

  • 执行 npm prefix -g 会输出全局安装路径
  • Windows 用户把输出的路径添加到环境变量 %PATH% 里面,环境变量的设置请参考 百度
  • 类 Unix 用户把 $(npm prefix -g)/bin 目录设置到 PATH 中。
    • bash echo -e "export PATH=$(npm prefix -g)/bin:$PATH" >> ~/.bashrc && source ~/.bashrc
    • zsh echo -e "export PATH=$(npm prefix -g)/bin:$PATH" >> ~/.zshrc && source ~/.zshrc