原理
代理也称网络代理,是一种特殊的网络服务,允许一个终端(一般为客户端)通过这个服务与另一个终端(一般为服务器)进行非直接的连接。- 维基百科
在项目开发(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" } }, ] 复制代码
你会发现我们并没有写任何服务,但是却能够请求到真实的数据。表示我们的代理服务已经成功运行了。
我建议你如果还不是很理解这个代理服务和这些配置的作用,什么代理不代理,替不替换前缀的,你可以多尝试着修改配置,看看真实代理的表现。
感谢阅读,今天的内容就到这里了哦,嘻嘻嘻,记得给我点赞和关注哦。