response.setHeader 用法与常见错误
response.setHeader 是服务端往 HTTP 响应里写头信息的方法。ASP 里是 Response.SetHeader,Java Servlet 里是 response.setHeader,Node.js 里是 res.setHeader。名字一样,用法有差别,踩的坑却是同一批。
一、基本用法
// ASP
Response.SetHeader "Content-Type", "text/html; charset=utf-8"
// Java Servlet
response.setHeader("Content-Type", "application/json;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
// Node.js
res.setHeader('Content-Type', 'application/json');
res.setHeader('X-Request-Id', 'abc123');
二、setHeader 和 addHeader 的区别
setHeader 是覆盖:同名头已经存在时,把旧值替换掉。addHeader 是追加:同名头可以出现多次,值以逗号分隔(Java 里实际是新增一个同名字段)。
需要多个值的场景,比如 Set-Cookie,必须用 addHeader,用 setHeader 会让前面设置的 Cookie 丢失:
response.addHeader("Set-Cookie", "a=1; Path=/");
response.addHeader("Set-Cookie", "b=2; Path=/");
三、最常见的五个错误
1. 响应已经提交后再设置头
Java 里报 java.lang.IllegalStateException: Cannot set a header after the response has been committed。原因是在 out.write() 或 out.flush() 之后才调用 setHeader。解决办法是把所有 header 设置放在写响应体之前,或者用 buffer 加大缓冲区。
2. 中文乱码
Content-Type 只写 text/html 不写 charset,浏览器会按本地编码猜,中文必然乱。正确写法是 text/html; charset=utf-8,并且 setCharacterEncoding 要在这之前调用,否则不生效。
3. 重定向写错
response.setStatus(302);
response.setHeader("Location", "/login");
只写 Location 不改状态码,浏览器不会跳转,会当成普通响应处理。用 sendRedirect 更省事,它会自动处理状态码和编码。
4. 跨域头写重复
Access-Control-Allow-Origin 设置两次会导致浏览器报 "The 'Access-Control-Allow-Origin' header contains multiple values"。常见于网关和业务代码各加了一遍。要么只在网关加,要么业务代码里判断已存在就不加。
5. 下载文件名乱码
response.setHeader("Content-Disposition",
"attachment; filename*=UTF-8''" + URLEncoder.encode(name, "UTF-8"));
老写法 filename=中文 在部分浏览器里会乱,用 RFC 5987 的 filename* 更稳。
四、几个实用头
- Cache-Control:no-store 禁止缓存,max-age=3600 缓存一小时
- X-Content-Type-Options: nosniff:禁止浏览器猜测内容类型,防 XSS
- X-Frame-Options: DENY:禁止被 iframe 嵌套,防点击劫持
- Strict-Transport-Security:强制 HTTPS
- Content-Security-Policy:限制资源加载来源
五、调试时怎么看
浏览器 F12 → Network → 点请求 → Response Headers,能看到最终发出的所有头。如果代码里设了但这里看不到,说明被中间的 Nginx 或 CDN 改写了,或者是响应提交后才设置导致没生效。curl -I 看一遍原始响应也很直接。