一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
原理
代理也称网络代理,是一种特殊的网络服务,允许一个终端(一般为客户端)通过这个服务与另一个终端(一般为服务器)进行非直接的连接。- 维基百科
在项目开发(dev)中,所有的网络请求(包括资源请求)都会通过本地的 server 做响应分发,我们通过使用 http-proxy-middleware 中间件,来代理指定的请求到另一个目标服务器上。如请求 featch('/api')
来取到远程 http://jsonplaceholder.typicode.com/
的数据。
要实现上述的需求我们只需要在配置文件中使用 proxy 配置:
export default {
proxy: {
'/api': {
'target': 'http://jsonplaceholder.typicode.com/',
'changeOrigin': true,
'pathRewrite': { '^/api' : '' },
},
},
}
上述配置表示,将 /api
前缀的请求,代理到 http://jsonplaceholder.typicode.com/
,替换请求地址中的 /api
为 ''
,并且将请求来源修改为目标url。如请求 /api/a
,实际上是请求 http://jsonplaceholder.typicode.com/a
。
一般我们使用这个能力来解开发中的跨域访问问题。由于浏览器(或者 webview)存在同源策略,之前我们会让服务端配合使用 Cross-Origin Resource Sharing (CORS) 策略来绕过跨域访问问题。现在有了本地的 node 服务,我们就可以使用代理来解决这个问题。
XMLHttpRequest cannot load api.example.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
原理其实很简单,就是浏览器上有跨域问题,但是服务端没有跨域问题。我们请求同源的本地服务,然后让本地服务去请求非同源的远程服务。需要注意的是,请求代理,代理的是请求的服务,不会直接修改发起的请求 url。它只是将目标服务器返回的数据传递到前端。所以你在浏览器上看到的请求地址还是 http://localhost:8000/api/a
。
值得注意的是 proxy 暂时只能解开发时(dev)的跨域访问问题,可以在部署时使用同源部署。如果在生产上(build)的发生跨域问题的话,可以将类似的配置转移到 Nginx 容器上。
实现
安装模块
cd packages/malita
pnpm i http-proxy-middleware
类型定义
我们在 packages/malita/src/config.ts
定义一个配置 proxy 类型
import type { Options as ProxyOptions } from 'http-proxy-middleware';
export interface UserConfig {
title?: string;
keepalive?: any[];
+ proxy?: { [key: string]: ProxyOptions };
}
使用 http proxy 中间件
import { createProxyMiddleware } from 'http-proxy-middleware';
const buildMain = async ({ appData }: { appData: AppData }) => {
// 获取用户数据
const userConfig = await getUserConfig({
appData, malitaServe
});
// 略 getRoutes generateEntry generateHtml
if (userConfig.proxy) {
Object.keys(userConfig.proxy).forEach((key) => {
const proxyConfig = userConfig.proxy![key];
const target = proxyConfig.target;
if (target) {
app.use(
key,
createProxyMiddleware(key, userConfig.proxy![key],),
);
}
});
}
}
我们判断如果用户设置了 proxy 就使用 http-proxy-middleware
中间件。
项目中配置使用
examples/app/malita.config.ts
export default {
title: 'Hello',
keepalive: [/./, '/users'],
proxy: {
'/api': {
'target': 'http://jsonplaceholder.typicode.com/',
'changeOrigin': true,
'pathRewrite': { '^/api': '' },
}
}
}
运行验证
cd examples/app
pnpm dev
> malita dev
App listening at http://127.0.0.1:8888
[HPM] Proxy created: /api -> http://jsonplaceholder.typicode.com/
[HPM] Proxy rewrite rule created: "^/api" ~> ""
仔细看日志说明,就是我们前面提到的将 /api
前缀的请求,代理到 http://jsonplaceholder.typicode.com/
,替换请求地址中的 /api
为 ''
,并且将请求来源修改为目标url。如请求 /api/a
,实际上是请求 http://jsonplaceholder.typicode.com/a
。
浏览器中访问 http://127.0.0.1:8888/api/users
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
]
你会发现我们并没有写任何服务,但是却能够请求到真实的数据。表示我们的代理服务已经成功运行了。
我建议你如果还不是很理解这个代理服务和这些配置的作用,什么代理不代理,替不替换前缀的,你可以多尝试着修改配置,看看真实代理的表现。
感谢阅读,今天的内容就到这里了哦,嘻嘻嘻,记得给我点赞和关注哦。