在我把博客开发的差不多的时候,准备部署时,前后端分离的两个服务如何考虑到编排部署
原计划使用反向代理的方式解决跨域、统一应用SSL证书,如下图:
flowchart TD A[Nginx:80] -->|rewrite| B(Nginx:443) B -->|path:/| C[nuxt] B -->|path:/api| D[api]
然而~问题出现了:打开页面直接报了一个莫名的错误,通过后端日志排查: 发现nuxt3在服务端无法直接请求
https
导致。
[14:09:44] [nuxt] [request error] [unhandled] [500] request to https://api.example.com failed, reason: unable to verify the first certificate (https://api.example.com)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async $fetchRaw2 (./node_modules/ofetch/dist/shared/ofetch.d438bb6f.mjs:215:14)
at async sendProxy (./node_modules/h3/dist/index.mjs:521:20)
at async Object.handler (./node_modules/h3/dist/index.mjs:1284:19)
at async Server.toNodeHandle (./node_modules/h3/dist/index.mjs:1359:7)
但nuxt3
与strapi
的沟通需要在服务端能通过http协议沟通,在客户端能通过https协议。
所以只能通过 nuxt3
内网代理 strapi
后端来解决此问题
解决方案
flowchart TD A[Nginx:80] -->|rewrite| B(Nginx:443) B -->|path:/| C[nuxt] C -->|path:/api| D[api]
方案一:nitro.routeRules
那就开始看 nitro 文档,找到了 nitro.routeRules
属性的配置 属性文档
但我却发现无法代理返回静态资源,我的媒体库是
strapi
集成的本地媒体库,静态资源使用存储桶方案或另外反向代理的话也可以使用此方案
// nuxt.config.js
nitro: {
routeRules: {
'/api/**': { proxy: 'http://backend-service:1337/**' },
}
},
方案二:nuxt server
还在我不停的搜索下,发现了 nitro
使用 unjs/h3
库完成路由功能等,h3
库中有个 sendProxy
方法, 也可以完美代理后端
在项目中创建了此文件 server/router/api/[...path].ts
//server/router/api/[...path].ts
import { sendProxy } from "h3"
export default defineEventHandler(async (event) => {
let path = event.node.req.url?.replace(/^\/api\/(.*)/, "/$1");
return await sendProxy(event, "http://backend-service:1337/:" + path)
})
总结
nuxt3 基于 nitro
中引用的 unjs/ofetch
在请求时不支持 https 的问题也是很迷,也不知是不是 nuxt2
就如此,毕竟很多时候接口服务可能已经直接上了 SSL
,可能就需要应用方案2,并使用如 node-http-proxy 等库进行代理等。