Closed zhaobinglong closed 2 years ago
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'ip',
user : 'xxxx',
password : 'xxxx',
database : 'xxxxx'
});
connection.connect();
connection.query('SELECT * from user', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
const EventEmitter = require('events');
class Player extends EventEmitter {}
var player = new Player()
player.on('play', (track) => {
console.log(`正在播放《${track}》`)
})
player.emit('play', '黑凤凰')
player.emit('play', '复仇者联盟4')
默认情况下,如果一个事件的监听函数超过10个,EventEmitters对象将会打印一个警告信息.这是一个发现内存溢出很有用的方法.很明显不是所有的Emitters对象都应该限制10个监听器.这个函数将会允许增加限制个数,如果不想限制个数,可以设置为0.
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 6 pipe listeners added to [Request]. Use emitter.setMaxListeners() to increase limit
fs 本身提供了 readFile 和 writeFile,它们好用的代价就是性能有问题,会将内容一次全部载入内存。但是对于几 GB 的大文件,显然会有问题。
那么针对大文件的解决方案自然是:一点点读出来。这就需要用到 stream 了。以 readStream 为例
var http = require('http');
var fs = require('fs');
// 利用stream,读取data.txt文件到内存,然后返回
var server = http.createServer(function (req, res) {
let stream = fs.createReadStream(__dirname + '/data.txt');//创造可读流
stream.pipe(res);//将可读流写入response, pipe方法如同stream和response之间的一个管道,将data.txt文件一小段一小段地发送到客户端,减小了服务器的内存压力。
});
server.listen(8000);
Readable - 可读的流 (例如 fs.createReadStream()). Writable - 可写的流 (例如 fs.createWriteStream()). Duplex - 可读写的流 (例如 net.Socket). Transform - 在读写过程中可以修改和变换数据的 Duplex 流 (例如 zlib.createDeflate()
let fs = require('fs');
//通过创建一个可读流
let rs = fs.createReadStream('./1.txt',{
flags:'r',//我们要对文件进行何种操作
mode:0o666,//权限位
encoding:'utf8',//不传默认为buffer,显示为字符串
start:3,//从索引为3的位置开始读
//这是我的见过唯一一个包括结束索引的
end:8,//读到索引为8结束
highWaterMark:3//缓冲区大小
});
rs.on('open',function () {
console.log('文件打开');
});
rs.setEncoding('utf8');//显示为字符串
//希望流有一个暂停和恢复触发的机制
rs.on('data',function (data) {
console.log(data);
rs.pause();//暂停读取和发射data事件
setTimeout(function(){
rs.resume();//恢复读取并触发data事件
},2000);
});
//如果读取文件出错了,会触发error事件
rs.on('error',function () {
console.log("error");
});
//如果文件的内容读完了,会触发end事件
rs.on('end',function () {
console.log('读完了');
});
rs.on('close',function () {
console.log('文件关闭');
});
/**
文件打开
334
455
读完了
文件关闭
**/
HTTP服务器用于响应来自客户端的请求,当客户端请求数逐渐增大时服务端的处理机制有多种,如tomcat的多线程、nginx的事件循环等。而对于node而言,由于其也采用事件循环
和异步I/O
机制,因此在并发的场景下性能非常好,但是由于单个node程序仅仅利用单核cpu,因此为了更好利用系统资源需要fork多个node进程执行HTTP服务器逻辑,所以node内建模块提供了child_process和cluster模块。
const cluster = require('cluster');
const http = require('http');
// 计算当前的服务器CPU数量
const numCPUs = require('os').cpus().length;
// 如果是主线程,就去fork子线程,有多少个CPU就fokr多少个
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
});
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
}
这里的三行代码就是cluster.js的全部内容,可以看出,子进程和主进程的区分是通过‘NODE_UNIQUE_ID’来判断的。我们分析cluster.fork方法可以发现,在createworkprocess中都会对NODE_UNIQUE_ID进行赋值,而master进程中是没有NODE_UNIQUE_ID的。所以再demo程序中可以分别在主进程和子进程中执行不同的内容。因此主进程执行完后,就仅仅fork出了子进程。
'use strict';
const childOrMaster = 'NODE_UNIQUE_ID' in process.env ? 'child' : 'master';
module.exports = require(`internal/cluster/${childOrMaster}`);
子进程服务没有创建对底层服务端socket的进行监听,所以自然不会出现子进程端口复用的情况。最后,调用cb函数,将fake后的handle传递给上层net.Server,设置net.Server对底层的socket的引用。此后,子进程利用fake后的handle做端口侦听(其实压根啥都没有做),执行成功后返回。
function rr(message, indexesKey, cb) {
if (message.errno)
return cb(message.errno, null);
var key = message.key;
function listen(backlog) {
// TODO(bnoordhuis) Send a message to the master that tells it to
// update the backlog size. The actual backlog should probably be
// the largest requested size by any worker.
return 0;
} //... const handle = { close, listen, ref: noop, unref: noop }; handles[key] = handle; cb(0, handle);
}
子进程TCP服务器没有创建底层socket,它主要依赖IPC通道与主进程通信,既然主进程负责接受客户端请求,那么理所应当由主进程分发客户端请求给某个子进程,由子进程处理请求。具体分配给哪个子进程处理,是由round-robbine分发策略(本质上就是轮询算法)来决定的。由于子进程在server中设置了对底层的socket的引用,所以子进程接收到任务后,触发connection事件开始执行业务逻辑。
对于该部分还需要持续关注,因为涉及底层libuv,需要结合C++代码一起理解。比如:IPC通信方式有多种,node.js是如何决定使用哪种方式来通信?
https://www.cnblogs.com/novak12/p/9304617.html https://segmentfault.com/a/1190000021230376 https://blog.csdn.net/xtx1990/article/details/8437622
// 服务器端return global提示如下错误
0|www | TypeError: Converting circular structure to JSON
0|www | --> starting at object with constructor 'global'
0|www | --- property 'global' closes the circle
0|www | at JSON.stringify (<anonymous>)
0|www | at stringify (/Users/zhaobinglong/Desktop/github/nurse-helper/api/node_modules/_express@4.16.4@express/lib/response.js:1119:12)
0|www | at ServerResponse.json (/Users/zhaobinglong/Desktop/github/nurse-helper/api/node_modules/_express@4.16.4@express/lib/response.js:260:14)
0|www | at Request._callback (/Users/zhaobinglong/Desktop/github/nurse-helper/api/routes/wechat.js:26:13)
0|www | at Request.self.callback (/Users/zhaobinglong/Desktop/github/nurse-helper/api/node_modules/_request@2.88.2@request/request.js:185:22)
0|www | at Request.emit (events.js:311:20)
0|www | at Request.<anonymous> (/Users/zhaobinglong/Desktop/github/nurse-helper/api/node_modules/_request@2.88.2@request/request.js:1154:10)
0|www | at Request.emit (events.js:311:20)
0|www | at IncomingMessage.<anonymous> (/Users/zhaobinglong/Desktop/github/nurse-helper/api/node_modules/_request@2.88.2@request/request.js:1076:12)
0|www | at Object.onceWrapper (events.js:417:28)
0|www | WARNING: NODE_APP_INSTANCE value of '0' did not match any instance config file names.
0|www | WARNING: See https://github.com/lorenwest/node-config/wiki/Strict-Mode
global不能直接被ruturn,因为其中包含了很多服务器端特有的函数或者方法,可以return其中的某个对象
global.poquanyundong = {
token: body.access_token,
expires_time: new Date().getTime() + 7200
}
JSON Web Token(缩写 JWT)是一种跨域认证解决方案。服务器认证以后,生成一个字符串,发回给用户,为了防止用户篡改数据,服务器在生成这个字符串的时候,会加上签名。以后,用户与服务端通信的时候,都要带上这个字符串。服务器完全只靠这个字符串认定用户身份。字符串的形式如下这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
这个字符串我们可以称之为JWT。JWT字符串可以在官网上jwt.io/去解析出来。解析出来后,发现有三个部分。仔细看JWT字符串,有两个点(.)把字符串分隔开了,其实就是和解析后的结构一一对应。 这三个部分就是JWT的数据结构。分别是Header(头部),Payload(负载),Signature(签名)。
https://www.jianshu.com/p/576dbf44b2ae https://zhuanlan.zhihu.com/p/86937325
自定义过滤器filter
在src根目录下新建filters文件夹,新建index.js编辑项目所有的过滤
在main中全局自动注册filter