Astro 设置 Cookie 后重定向报 immutable:换用上下文响应
开发正常,生产 endpoint 设置 Cookie 后返回 Response.redirect 却报 500。区分只读响应头与业务重定向,用 Astro 的 redirect 或可写响应承载 Cookie。
endpoint 先调用 cookies.set(),再返回 Response.redirect(),开发模式正常,Node 生产构建却返回 500,日志指向 prepareResponse 的 TypeError: immutable。如果返回的是 fetch 得到的 Response,也应检查它的响应头是否允许修改。
明确的组合包含 Astro 7.3.6、@astrojs/node 11.1.7 和 server 输出。当前正式 Astro 7.4.2 的 prepareResponse 仍直接向返回响应追加 Set-Cookie,因此不要只更新 Astro 主包就承诺所有只读 Response 都能被修改。
Cookie 需要追加到最终发送的响应上
Response.redirect() 创建的响应、fetch 返回的网络响应,可能具有不可修改的 headers。Astro 的 Cookie API 暂存了设置值,生产路径准备发送时再向响应头追加;此时对只读 headers 调用 append 就会失败。
开发服务器可以通过 Node 响应接口写入头部,并不一定修改同一个 Headers 对象。两条发送路径不同,开发通过后仍需核对生产适配器能否追加头部。
重定向优先使用上下文的 redirect
需要设置 Cookie 再跳转时,使用 endpoint 上下文提供的 redirect。下面以无敏感性的布局偏好 Cookie 为例:
import type { APIRoute } from 'astro';
export const GET: APIRoute = ({ cookies, redirect }) => {
cookies.set('layout', 'compact', { path: '/' });
return redirect('/dashboard', 302);
};
该路由必须在实际请求时执行;静态预渲染不适合按访客请求设置 Cookie。示例不是登录或会话实现,真实认证 Cookie 的值、属性、期限和重定向目标仍按应用原策略处理。
返回普通上游响应时,可以在 body 尚未被读取或锁定的前提下,重建一个有可写头部的普通 Response:
const response = new Response(upstream.body, {
status: upstream.status,
statusText: upstream.statusText,
headers: new Headers(upstream.headers),
});
return response;
这里 upstream 是已有 fetch 结果,片段用于原 endpoint 的返回位置。它接管同一条 body 流,不应再同时消费旧响应;也不适用于 WebSocket 升级等普通 Response 构造器无法完整表达的扩展语义。代理场景还需保留原来的响应头筛选与权限规则,不能把复制所有上游头当成安全策略。
不要通过先调用 headers.append() 再返回原 Response 来绕行,同一对象的头仍然不可写。Response.clone() 主要复制响应体的读取分支,也不应被当成解除 headers 只读限制的开关。
验收使用构建后的原 Node 服务,检查跳转状态、Location 和 Set-Cookie 同时正确;代理响应则核对状态、正文与必要头部。再确认浏览器在预期路径和协议下保存、发送 Cookie。仅 curl 看到一个头,不代表真实会话或浏览器 Cookie 策略全部正确。


