// "apn": "^2.1.2",
var apn = require('apn');
var service = new apn.Connection(
"passphrase":"secret",
"pfx":"/path/to/cert.p12",
"production":false
});
var apnVoipProvider = new apn.Provider(voipOptions);
apnNotification = new apn.Notification();
apnNotification.badge = 1;
apnNotification.sound = 'msg.mp3';
apnNotification.alert = 'hello';
apnNotification.payload = {
title: notification.title, id: notificationID, path: notification.path,
};
apnVoipProvider.send(apnNotification, token);
31 篇博文 含有标签「node.js」
查看所有标签怎样获得 express 所有的注册路由呢?
比如我们注册了如下的路由
app.get('/', function (...) { ... });
app.get('/foo/:id', function (...) { ... });
app.post('/foo/:id', function (...) { ... });
然后想要获得的东东是这样的形式:
{
get: [ '/', '/foo/:id' ],
post: [ '/foo/:id' ]
}
该肿么办呢?
在 express 3.x 中
只需要 app.routes
就可以啦
在 express 4.x 中
Applications - built with express()
app._router.stack
Routers - built with express.Router()
router.stack
更多的答案尽在 StackOverflow how-to-get-all-registered-routes-in-express
node.js 通过 tcp 方式获取随机端口与使用场景
某些场景可能需要动态的获取端口来启动服务,可能服务化场景,不直接硬配置端口。
哈哈,这看来是要为分布式、服务注册、服务发现做准备呢。
/**
* 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 即可实现服务发现,不过还木有实践。
node.js 实现文件下载
文件下载实际上是二进制流的发送,所以在服务端是就向客户端写流。
而在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:用自然语言去编写正则表达式
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
文档
node.js rabbitmq(amqplib) 断线重连
我用的是amqplib 这个包,github上的项目名是amqp.node
这个包貌似是没有实现断线自动重连的,看了看issues,也和我自己实现的版本差不多。
思路
思路主要是两个地方:
- connection实例的
error
事件. - 初始化的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 )
可以像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 全局安装了却找不到这个命令
大家都知道,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
- 用
node.js单元测试之带session和cookie的案例
需要cookie和session的测试案例
在web开发中,Cookie有着非常重要的作用。因为HTTP是无状态的,所以需要用cookie来辅助实现用户认证。我们先来简单介绍一下cookie的工作机制。
如果所示,如果通过cookie和session协同识别一个用户需要两次请求,第一次请求的时候,服务器并不认识你,但是他给你标记了一个他独有的id,等到第二次请求的时候,浏览器自动给你带上了之前的标签,这样服务器就知道你之前请求过了。
那么问题来了,如果我们写测试案例的时候,需要两次请求来实现的话,会非常麻烦,测试案例也会很冗长。怎么才能一次请求就能使用cookie和session呢?
这时候express的中间件的好处就体现了。
首先,我们在用supertest
进行HTTP请求的时候,可以通过下面的形式设置cookie:
set('Cookie', cookieValue)
然后,我们写一个非常简单的中间件:
app.use(function(req, res, next) {
if (config.debug && req.cookies['mock_user']) {
var mockUser = JSON.parse(req.cookies['mock_user']);
req.session.user = new UserModel(mockUser);
return next();
}
next();
});
原理就是先判断当前是否为开发环境,通过config来设置,通常在开发阶段这个值设置为true。其次判断是否具有键为mock_user的cookie键值对,如果存在,设置session里面的user值,这样,只要一次请求我们就能实现用户标识。 最后要解决的问题就是怎么设置字段键为mock_user的cookie了,具体的用法可参照test目录里面的support/support.js,这里不多说。
补充
测试时加上
.set('Cookie', cookie)
那么这个cookie是什么形式呢?
Cookie: mock_user=xxxxxxxxxx
var cookie = [ 'mock_user', encodeURIComponent(JSON.stringify(support.user))].join('=');
node.js 判断当前模块是否是程序的入口
看别人写的node.js代码的时候,看到有很多地方会有这么一个写法。
// start the server if `$ node server.js`
if (require.main === module) {
//to do something
}
其实这就是判断当前模块是否是程序的入口。