Nuxt.js SSR下asyncData避免公网二次请求调用Express接口的方案问询
Nuxt.js SSR 配合Express环境免公网调用本地API的解决方案
核心思路
抽离API业务逻辑为独立纯函数层,服务端渲染时直接调用逻辑层方法,完全跳过HTTP网络请求环节,同时保证客户端侧原有API调用逻辑不变、两端业务逻辑完全一致。
1. 抽离独立API逻辑模块
将原本写在Express路由里的业务逻辑和HTTP请求/响应逻辑解耦,单独封装为不依赖Web服务的纯函数模块,就是你期望的apimodule形态:
// /server/apimodule.js // 各业务接口逻辑单独实现,仅依赖入参,不绑定HTTP对象 const resourceService = { async getResource(params, userInfo = {}) { // 此处写入原本的数据库查询、业务处理逻辑 // const result = await db.table('resources').where(params).find() return { code: 200, data: {}, msg: '查询成功' } } } // 统一暴露请求调度方法 export default { async handle(request) { const { path, method, query, body, user } = request // 根据请求路径、方法分发到对应业务逻辑 switch (true) { case path === '/api/resource' && method === 'GET': return resourceService.getResource(query, user) // 其余接口路由规则依次补充即可 default: return { code: 404, msg: '接口不存在' } } } }
2. 复用逻辑模块兼容原有客户端API调用
原有Express的API路由无需重写业务逻辑,直接调用封装好的apimodule即可,保证客户端发起的公网API请求和服务端本地调用逻辑完全一致:
// /server/routes/api.js import apimodule from '../apimodule.js' app.get('/api/resource', async (req, res) => { const result = await apimodule.handle(req) res.json(result) }) // 其余API路由同理实现
3. Nuxt服务端注入API模块
通过Nuxt服务端专属插件,将apimodule注入到Nuxt上下文对象中,仅服务端渲染时可调用,不会打包到客户端代码:
// /plugins/api.server.js 后缀.server表示仅服务端加载 import apimodule from '~/server/apimodule.js' // Nuxt3写法,Nuxt2调整对应注入语法即可 export default defineNuxtPlugin((nuxtApp) => { nuxtApp.provide('localApi', apimodule) })
4. 页面asyncData适配双端调用
在asyncData中判断运行环境,服务端直接调用本地逻辑,客户端走正常公网请求,完全符合你期望的调用形态:
export default { async asyncData({ params, $http, $localApi, req }) { let post if (process.server) { // 服务端直接调用本地逻辑,无任何网络开销 const apiResult = await $localApi.handle(req) post = apiResult.data } else { // 客户端走正常公网API请求 post = await $http.$get(`/api/resource`) } return { post } } }
方案优势
- 完全消除服务端渲染时的二次公网请求开销,页面加载延迟大幅降低
- API业务逻辑仅维护一份,两端调用不会出现逻辑不一致问题
- 无需在Vue文件中直接引入数据库模块,业务分层清晰,符合架构规范
- 增量改造成本极低,原有客户端调用逻辑完全不需要调整
内容的提问来源于stack exchange,提问作者myestery
相关产品推荐
相关产品推荐

