我正在阅读如何使用服务器操作通过从不将此类数据发送到客户端来将敏感数据保留在服务器上。例如,我认为这对于保留访问令牌可能很有用。然后,我在客户端编写代码来调用服务器操作来执行特权操作。这工作正常,但需要注意的是,如果在构建步骤中执行此设置,则该设置将不起作用。
我在服务器上有类似的东西,它使用
axios
拦截器 将访问令牌插入到每个请求的授权标头中。
axios.interceptors.request.use(async req => {
const session = await getServerSession(authOptions)
req.headers.authorization = `Bearer ${session.access_token}`;
return req;
});
但是,
getServerSession()
在编译路线时会导致问题。也就是说,当使用例如npm run build
直接或在使用例如时进行服务器操作调用时
generateStaticParams
。无论哪种情况,您都会看到类似的错误。
rpm run build
Error: Invariant: headers() expects to have requestAsyncStorage, none available.
at u (/mnt/.next/server/chunks/472.js:30:26016)
at s (/mnt/.next/server/chunks/472.js:30:20315)
at /mnt/.next/server/chunks/881.js:1:10082
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async m (/mnt/.next/server/chunks/881.js:1:9490)
at async Object.x [as generateStaticParams] (/mnt/.next/server/app/posts/[slug]/page.js:1:3453)
at async buildParams (/mnt/node_modules/next/dist/build/utils.js:1025:40)
npm run dev
Error: Invariant: headers() expects to have requestAsyncStorage, none available.
at headers (webpack-internal:///(rsc)/./node_modules/next/dist/client/components/headers.js:38:15)
at getServerSession (webpack-internal:///(rsc)/./node_modules/next-auth/next/index.js:107:41)
at eval (webpack-internal:///(rsc)/./lib/server.ts:32:86)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async getAllPosts (webpack-internal:///(rsc)/./lib/server.ts:43:9)
at async Object.generateStaticParams (webpack-internal:///(rsc)/./app/posts/[slug]/page.tsx:32:13)
at async buildParams (/mnt/node_modules/next/dist/build/utils.js:1025:40)
✓ Compiled /editor/update/[slug] in 216ms (1737 modules)
我的代码大致如下:
/app/posts/[slug]/page.tsx
export async function generateStaticParams() {
return (await getAllPosts()).map((slug: string) => ({ slug }))
}
/lib/server.ts
'use server'
axios.interceptors.request.use(async req => {
const session = await getServerSession(authOptions)
req.headers.authorization = `Bearer ${session.access_token}`;
return req;
});
export async function getAllPosts(): Promise<string[]> {
let slugs: string[] = []
await axios.get('/api/slugs/).then((r) => {
slugs = r.data
})
return slugs
}
知道这是怎么回事吗?我是否做了一些明显不正确的事情?流程是:
generateStaticParams (during build)
->
getAllPosts (server)
->
getServerSession (server)
在服务器操作中使用 axios 拦截器似乎确实有效 - 它只是在任何类型的编译步骤中调用时不起作用。 有什么想法吗?我在这里做错了什么?构建期间当然没有“会话”。尽管我期望它返回 null 或类似的值,而不是抛出错误。也许答案就是抓住它而不做任何事情?
getServerSession(authOptions)
,这会导致错误,因为
getServerSession
函数依赖于在构建或静态生成期间不可用的服务器端功能。这里有两种解决方法:
:仅当拦截器在服务器上运行时才附加拦截器。您可以检查 process.browser
是否为
true
来确定代码是在浏览器中运行还是在服务器上运行。if (process.browser) {
axios.interceptors.request.use(async req => {
const session = await getServerSession(authOptions)
req.headers.authorization = `Bearer ${session.access_token}`;
return req;
});
}
这样,拦截器仅在客户端运行时使用,并且不会在构建步骤期间干扰服务器端操作。
:如果您在服务器操作中使用getServerSession
,则可以在构建或静态生成期间调用时提供后备或默认值。这可以帮助防止错误。
export async function getServerSessionFallback(authOptions) {
if (process.browser) {
return getServerSession(authOptions);
} else {
// Provide a fallback value (e.g., null) for server-side usage during build.
return null;
}
}
然后,在拦截器或服务器操作中使用
getServerSessionFallback
。