1、需求
前后端分离项目中,需要使用反向代理,已解决跨域访问问题,在这里需要了解正向代理、反向代理等概念,
2、正向代理
正向代理比较好理解,类似于一个跳板,用来代替客户访问外部资源。
例如:
A向C借钱,由于一些情况不能直接向C借钱,于是A想了一个办法,他让B去向C借钱,这样B就代替A向C借钱,A就得到了C的钱,C并不知道A的存在,B就充当了A的代理人的角色。
总的来说:
正向代理(forward proxy) ,一个位于客户端和原始服务器之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并制定目标(原始服务器),然后代理向原始服务器转发请求并将获得的内容返回给客户端,客户端才能使用正向代理。
3、反向代理
反向代理(Reverse Proxy),以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求的客户端,此时代理服务器对外表现为一个反向代理服务器。
理解起来有些抽象,可以这么说:A向B借钱,B没有拿自己的钱,而是悄悄地向C借钱,拿到钱之后再交给A,A以为是B的钱,他并不知道C的存在。
4、node插件http-proxy实现反向代理
前端web服务器选择express,使用 http-proxy 实现反向代理:
const _ = require('lodash');
const path = require('path');
const httpProxy = require('http-proxy');
const request = require('request');
const chokidar = require('chokidar');
const proxyRespJson = require('node-http-proxy-json');const proxy = httpProxy.createProxyServer();
var mockData = {};
const mockDataPath = path.resolve(__dirname, '../mockData');// 监听mock文件变化,重新加载mock数据
chokidar.watch(mockDataPath).on('change', (filepath) => {
console.info('mock数据变化,重新加载', filepath);
loadMockData();
});// 加载mock数据
function loadMockData() {
try {
// require.cache对象, 代表缓存了所有已被加载模块的缓存区
Object.keys(require.cache).forEach((cachePath) => {
if (cachePath.startsWith(mockDataPath)) {
delete require.cache[cachePath];
}
});
mockData = require(mockDataPath);
} catch (error) {
console.error('加载mock数据异常', error);
}
}proxy.on('error', (err, req, res) => {
console.error('代理失败:', err);
res.writeHead(200, {
'Content-Type': 'text/plain;charset=UTF8'
});res.send('抱歉,代理服务器异常...');
});proxy.on('proxyReq', (proxyReq) => {
// HTTP请求由三部分组成,分别是:请求行,消息报头,请求正文。
// http auth是一种基础的用户验证,原理是将用户名:密码base64加密后放在http的请求头部Authorization 发给服务器
// restful api 的一个特点即无状态,每次对敏感资源的访问都需要进行登陆验证,可以用http auth来很好的开发restful api。// proxyReq.setHeader('Authorization', authorizationValue);
});proxy.on('proxyRes', (proxyRes, req, res) => {
console.log(`请求代理状态: ${proxyRes.statusCode} <==> path: ${req.path}`);
const useMockStatusCode = [200, 404, 403, 500];if (useMockStatusCode.indexOf(proxyRes.statusCode) !== -1) {
// 获取 writHead 方法,发送一个响应头给请求,这里获取此方法,改变响应头状态嘛
/* 参数列表:
* .writeHead(200, {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'text/plain'
})
状态码:如 404
headers 是响应头
* */
const _writeHead = res.writeHead
// writHead() 在消息中只能被调用一次,且必须在res.end()之前调用
// response.setHeader() 设置的响应头会与 response.writeHead() 设置的响应头合并,且 response.writeHead() 的优先Object.assign(res, {
writeHead: () => {
// 函数 apply() 方法,执行this为res,传递参数 200,
_writeHead.apply(res, [200, proxyRes.headers])
}
})proxyRespJson(res, proxyRes.headers['content-encoding'], (body) => {
console.info('请求远端服务异常,采用本地mock数据', req.path)
const callback = mockData[req.path]
// 传入req,用于部分mock获取request的数据
return callback ? callback(req) : {}
})
}
});module.exports = (app) => {
/*
* app.all()函数可以匹配所有的HTTP动词,也就是说它可以过滤所有路径的请求
* app.all(path,function(request, response))
* */
app.all("/api/v1/*", (req, res) => {
proxy.web(req, res,
{
target: "https://cnodejs.org",
changeOrigin: true, // 是否更改原始的host头字段为target url,默认为 false, 表示用于更改目标地址头信息
proxyTimeout: 10 * 60 * 1000
});
});
};// https://cnodejs.org/api/v1/topics
访问结果:
参考文章:
https://blog.csdn.net/zt15732625878/article/details/78941268
https://www.cnblogs.com/Anker/p/6056540.html