nodejs 方便了咱们前端开发者进行一些服务端上的操做,能够进行无缝地衔接。像其余一些后端语言,如 php, golang, java 等,都须要必定的学习成本,而 nodejs 则就是为前端开发者定制的。javascript
在 nodejs 中,提供了原生的 http 模块,咱们能够利用 http 模块搞几个经常使用的小工具,可以大大方便咱们的工做。php
我在以前从 0 到 1 学习 node(二)之搭建 http 服务器的文章中也讲解过 http 模块,不过咱们这里主要是利用 http 模块来打造几个使用的工具。html
使用 nodejs 搭建 http 服务很是地简单,只须要引入 http 模块便可:前端
// server.js const http = require('http'); const ip = '127.0.0.1'; const port = 3000; http .createServer((req, res) => { res.end('heelo world!'); }) .listen(port, ip); console.log(`server has started at ${ip}:${port}`);
而后执行 server.js 文件:java
$ node server.js
在控制台就会输出:node
server has started at 127.0.0.1:3000
而后在浏览器上访问http://127.0.0.1:3000
,就能看到hello world!的输出。ios
若是想在启动时,经过参数指定 IP 或端口。那么咱们能够经过process.env
来获取命令行中指定的参数:git
// 经过process.env来获取指定的参数 // 并设置兜底的数据 const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3000;
在执行 sever.js 时,就能够经过参数指定 IP 和端口:github
$ PORT=3030 node app.js
在作开发和调试过程当中,常常须要考虑到一个请求或者图片等加载很慢时,应该怎么处理。golang
好比有用户反馈某些图片加载很慢,致使页面看起来不正常。那么我就应该针对图片加载慢进行一些处理,但是怎么模拟这个加载很慢的图片呢?
不少现有的接口,都没法模拟出这种有特殊延迟的状况,这里咱们可使用 http 模块来实现。
咱们在第 1 个 http 服务器的基础上,进行改进。
res.end()方法会告知服务器当前次响应结束,若没有调用,则一直处于等待状态。
咱们要实现一个有延迟的响应,可使用 setTimeout 延迟调用 end()方法便可。这里先实现一个有延迟的接口。
http .createServer((req, res) => { const index = req.url.indexOf('?'); if (index >= 0) { const query = req.url.slice(index); const ss = new URLSearchParams(query); const timeout = ss.get('timeout'); const type = ss.get('type'); if (timeout && Number(timeout)) { return setTimeout(() => { if (type === 'json') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ code: 0, msg: 'hello world' })); } else if (type === 'image') { // 输出本地一个图片 } else { res.end(`delay ${timeout}ms response`); } }, Number(timeout)); } } res.end('hello world!'); }) .listen(port, ip);
想要延迟输出图片时,须要经过数据流的方式读取本地的图片,而后输出到前端:
const stream = fs.createReadStream('./img/s.jpg'); const responseData = []; //存储文件流 if (stream) { //判断状态 stream.on('data', function (chunk) { responseData.push(chunk); }); stream.on('end', function () { const finalData = Buffer.concat(responseData); // response.write(); res.writeHead(200, { 'Content-Type': 'image/jpg' }); res.end(finalData); }); }
咱们有时会遇到须要的接口存在跨域,或者是内网接口的问题,这时咱们就须要经过一个中间层,来对接口进行中转代理,才能正常地访问接口。
实现接口代理时要注意亮点:
跨域的方式有不少种,好比 jsonp 也是其中一种,但 cors 跨域是比较好的一种,前端能够有效地控制请求时间和取消请求。
在设置跨域头Access-Control-Allow-Origin
时,这里是不建议直接设置成*
。一方面是不安全,全部的域名均可以访问;再有就是前端不会再传送 cookie,没法进行一些登陆态的校验等。
在设置Access-Control-Allow-Origin
以前,咱们要先校验下 headers 中的 referer,若是为空或者不知足白名单的要求,则能够直接返回 403。
const allowList = ['joke.qq.com', 'www.qq.com']; if (!req.headers || !req.headers.referer) { res.writeHead(403, 'forbidden'); res.end('403 forbidden'); return; } const { hostname } = new URL(req.headers.referer); if (!allowList.includes(hostname)) { res.writeHead(403, 'forbidden'); res.end('403 forbidden'); return; }
知足要求以后,须要将 referer 最后的斜杠/
去掉,不然会设置不成功。完成的代码样例以下:
const http = require('http'); const https = require('https'); const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3001; http .createServer((req, res) => { const allowList = ['joke.qq.com', 'www.qq.com']; if (!req.headers || !req.headers.referer || allow) { res.writeHead(403, 'forbidden'); res.end('403 forbidden'); return; } console.log('发起请求', req.headers); https .get('https://www.v2ex.com/api/topics/latest.json', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { res.setHeader('Access-Control-Allow-Origin', (req.headers.referer || '').replace(/\/$/, '')); res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); res.end(data); }); }) .on('error', (e) => { console.error(`请求遇到问题: ${e.message}`, e); res.end('error'); }); }) .listen(port, ip); console.log(`server has started at ${ip}:${port}`);
若须要代理更多的接口,或者路径是从前端传过来的,咱们本身却是也能够实现,不过还有更方便的 proxy 代理组件了。
这里咱们用 http-proxy 组件来实现:
const http = require('http'); const httpProxy = require('http-proxy'); const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3000; const proxy = httpProxy.createProxyServer({ target: 'https://www.v2ex.com', // 代理的接口地址 changeOrigin: true, }); http .createServer((req, res) => { // 设置跨域头 res.setHeader('Access-Control-Allow-Origin', (req.headers.referer || '').replace(/\/$/, '')); res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); // 将请求和响应的对象传给proxy proxy.web(req, res); }) .listen(port, ip);
而后前端直接按照路径发起请求便可:
axios('http://localhost:3000/api/topics/latest.json').then(console.log).catch(console.error);
前端在写页面逻辑时,常常要考虑到数据的各类状况,好比无数据时,长列表,各类长度的昵称等。
不管是读取配置的 json 文件,仍是用代码生成的数据,都不具备随机性。
如今,咱们能够利用 mockjs 来实现各类数据的模拟:
const http = require('http'); const Mock = require('mockjs'); const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3000; http .createServer((req, res) => { const result = Mock.mock({ code: 0, msg: 'success', 'x-from': 'mock', data: Mock.mock({ 'rank|20': [ { 'no|+1': 1, // no 字段从 1 开始自增 uin: () => Mock.Random.string(32), // 32 长度的随机字符串 nick: () => Mock.Random.string(1, 20), // 长度在 1-20 之间的随机字符串 face: () => Mock.Random.image('120x120'), // 120*120 的图片 score: () => Mock.Random.integer(1, 2000), // 分数 }, ], }), }); res.setHeader('Access-Control-Allow-Origin', (req.headers.referer || '').replace(/\/$/, '')); res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(result, null, 2)); }) .listen(port, ip);
生成的数据:
关于 Mockjs 更多的语法规则,能够访问https://github.com/nuysoft/Mock/wiki/Getting-Started。
使用 nodejs 还能够实现更多的功能,这里咱们也仅仅是实现了其中简单的几个。基于咱们的前端知识和业务需求,咱们还能实现更多的小工具。
也欢迎您关注个人公众号:“前端小茶馆”