使用 nodejs 中的 http 模块实现几个超实用的工具,实战 java 虚拟机葛一鸣第二版 pdf
});
stream.on('end', function () {
const finalData = Buffer.concat(responseData);
// response.write();
res.writeHead(200, { 'Content-Type': 'image/jpg' });
res.end(finalData);
});
}
3. 实现接口的中转代理
我们有时会遇到需要的接口存在跨域,或者是内网接口的问题,这时我们就需要通过一个中间层,来对接口进行中转代理,才能正常地访问接口。
3.1 原生 http 模块来实现
实现接口代理时要注意亮点:
透传,接收到的所有数据,根据需要尽量都传给代理的接口,例如 cookie,参数等;
设置跨域头,为了方便前端的访问,我们需要在返回的头部加上 3 个可以跨域的字段;
跨域的方式有很多种,比如 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}
);
3.2 proxy 代理组件
若需要代理更多的接口,或者路径是从前端传过来的,我们自己倒是也可以实现,不过还有更方便的 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);
4. 模拟数据
前端在写页面逻辑时,经常要考虑到数据的各种情况,比如无数据时,长列
表,各种长度的昵称等。
无论是读取配置的 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);
生成的数据:
评论