如何在Next.js全局服务中获取Authorization头中的用户邮箱
解决方案:利用Node.js异步本地存储(AsyncLocalStorage)实现全局用户上下文
针对你的需求,我们可以用Node.js原生的AsyncLocalStorage来在异步调用链中传递用户邮箱上下文,不需要在每个API路由手动传递参数,完美适配你的限制条件。
实现步骤
1. 封装上下文管理工具
创建一个全局的上下文工具类,用来存储和获取请求级别的用户信息:
// src/utils/request-context.ts import { AsyncLocalStorage } from 'async_hooks'; // 定义上下文结构 type RequestContext = { userEmail: string; }; // 初始化异步本地存储实例 const asyncLocalStorage = new AsyncLocalStorage<RequestContext>(); // 执行回调并注入上下文 export const runWithContext = (context: RequestContext, callback: () => Promise<void>) => { return asyncLocalStorage.run(context, callback); }; // 获取当前上下文 export const getCurrentContext = () => { return asyncLocalStorage.getStore(); }; // 快捷获取当前用户邮箱 export const getCurrentUserEmail = () => { return getCurrentContext()?.userEmail; };
2. 编写API路由的上下文注入包装器
写一个高阶函数,统一处理所有API路由的用户邮箱提取和上下文注入逻辑:
// src/middleware/api-context-wrapper.ts import type { NextApiHandler } from 'next'; import { runWithContext } from '../utils/request-context'; // 从请求头解析用户邮箱(这里复用你middleware中已验证的token解码逻辑) const extractUserEmail = (req: NextApiRequest): string => { const authHeader = req.headers.authorization; if (!authHeader) throw new Error('未授权'); const token = authHeader.split(' ')[1]; // 替换成你实际的token解码逻辑(和middleware保持一致) const decodedToken = /* 解码token并获取email的代码 */; return decodedToken.email; }; // 包装API handler,注入用户上下文 export const withUserContext = (handler: NextApiHandler): NextApiHandler => { return async (req, res) => { try { const userEmail = extractUserEmail(req); // 注入上下文并执行原handler await runWithContext({ userEmail }, async () => { await handler(req, res); }); } catch (err) { res.status(401).json({ message: '身份验证失败' }); } }; };
3. 修改API路由使用包装器
给你的API路由加上上下文包装:
// pages/api/blogs/index.ts import type { NextApiRequest, NextApiResponse } from 'next'; import { container } from 'tsyringe'; import { ManageBlog } from '../../../src/module/blog/manage-blog'; import { withUserContext } from '../../../src/middleware/api-context-wrapper'; async function handler(req: NextApiRequest, res: NextApiResponse) { const manageBlog = container.resolve(ManageBlog); switch (req.method) { case 'GET': const loadedBlog = await manageBlog.readBlog(); res.status(200).json(loadedBlog); break; default: res.setHeader('Allow', ['GET']); res.status(405).end(`Method ${req.method} Not Allowed`); } } // 用上下文包装器导出handler export default withUserContext(handler);
4. 在服务类中直接获取用户邮箱
现在你的业务服务可以直接从上下文获取邮箱,无需依赖请求对象:
// src/module/blog/manage-blog.ts import { autoInjectable } from 'tsyringe'; import { getCurrentUserEmail } from '../../utils/request-context'; @autoInjectable() export class ManageBlog { public async readBlog() { const userEmail = getCurrentUserEmail(); if (!userEmail) { throw new Error('无法获取当前用户信息'); } // 这里直接使用userEmail做业务逻辑 console.log('当前操作用户:', userEmail); // 你的业务代码... return { /* 返回业务数据 */ }; } }
方案适配性说明
- 避开边缘环境限制:上下文注入逻辑运行在Next.js API路由的Node.js环境中,和边缘环境的middleware完全解耦
- 服务类无需直接访问请求头:通过上下文工具获取邮箱,实现了业务逻辑与请求对象的解耦
- 无需拦截器:用高阶函数实现统一的上下文注入,相当于轻量级的请求预处理逻辑
内容的提问来源于stack exchange,提问作者laprof
相关产品推荐
相关产品推荐

