目录
  • 解决方案
    • 方案一:nitro.routeRules
    • 方案二:nuxt server
  • 总结

在我把博客开发的差不多的时候,准备部署时,前后端分离的两个服务如何考虑到编排部署

原计划使用反向代理的方式解决跨域、统一应用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)

nuxt3strapi的沟通需要在服务端能通过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 等库进行代理等。

1692174861032.gif