Nodejs 响应头和请求头

请求头是浏览器发给服务器的"自我介绍",响应头是服务器回给浏览器的"回复说明"

响应头

服务器处理完请求后,返回给浏览器的"附加信息"。

常见响应头

响应头名称 作用 示例值
Content-Type 返回数据的格式 application/json
Content-Length 返回数据的字节大小 1024
Access-Control-Allow-Origin 允许跨域访问的来源(CORS) http://localhost:5500
Set-Cookie 设置Cookie sessionId=abc123; Path=/
Cache-Control 缓存策略 no-cache, max-age=3600
Server 服务器信息 Express
Status 状态码说明 200 OK
http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 15
Access-Control-Allow-Origin: http://localhost:5500
Cache-Control: no-cache

{"code":200}

请求头

浏览器发起请求时,自动携带的"附加信息"。

常见请求头

请求头名称 作用 示例值
Host 请求的目标服务器 localhost:3000
User-Agent 浏览器身份标识 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept 客户端能接收的数据格式 application/json, text/html
Accept-Encoding 客户端支持的压缩方式 gzip, deflate, br
Content-Type 请求体的数据格式(POST/PUT时) application/json
Authorization 身份认证令牌 Bearer eyJhbGciOiJIUzI1NiIs...
Cookie 携带的Cookie信息 sessionId=abc123
Origin 请求来源(跨域时重要) http://localhost:5500
http 复制代码
GET /info HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 Chrome/120.0
Accept: application/json
Origin: http://localhost:5500
Cookie: sessionId=abc123

响应头和请求头的区别

对比项 请求头 响应头
发送方 浏览器(客户端) 服务器
接收方 服务器 浏览器(客户端)
作用 告诉服务器"我是谁、要什么" 告诉浏览器"给你什么、什么规则"
谁设置 浏览器自动设置,JS可修改 服务器代码设置
关键字段 HostOriginCookieAuthorization Content-TypeAccess-Control-Allow-OriginSet-Cookie

在开发中,你只需要根据场景选择需要的请求头即可,不需要全部记住。比如,进行跨域请求时重点关注 Origin;发送 POST 请求时重点关注 Content-TypeAuthorization

响应头和跨域之间的关系

  • cors

跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种机制,用于在浏览器中实现跨域请求访问资源的权限控制。当一个网页通过 XMLHttpRequest 或 Fetch API 发起跨域请求时,浏览器会根据同源策略(Same-Origin Policy)进行限制。同源策略要求请求的源(协议、域名和端口)必须与资源的源相同,否则请求会被浏览器拒绝

右键Open with Live Server,直接打开http://127.0.0.1:5500/http-req-res-header/index.html,修改为http://localhost:5500/http-req-res-header/index.html

你用 Live Server 打开 HTML 文件时:

  • 页面地址http://127.0.0.1:5500/index.html(或 localhost:5500
  • 接口地址http://localhost:3000/info

端口不同(5500 vs 3000),浏览器认为是跨域请求,所以报 CORS 错误。

为什么 Live Server 会用 5500 端口?

Live Server 是一个轻量级开发服务器,默认端口是 5500 ,用于托管静态 HTML 文件。你的页面通过它访问,而接口跑在 3000 端口,两者端口不同 → 跨域。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        fetch('http://localhost:3000/info').then(res=>{
            return res.json()
        }).then(res=>{
            console.log(res)
        })
    </script>
</body>
</html>
js 复制代码
import express from 'express'
const app = express()
// app.use((req, res, next) => {
//     res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5500')
//     next()
// })
app.get('/info', (req, res) => {
    res.json({
        code: 200
    })
})
app.listen(3000, () => {
    // console.log('http://localhost:3000')
})

发现是有报错的 根据同源策略我们看到协议一样,域名一样,但是端口不一致,端口也无法一致,会有冲突,否则就是前后端不分离的项目,前后端代码放在一起,只用一个端口,不过我们是分离的没法这么做。

这时候我们就需要后端支持一下,跨域请求资源放行

js 复制代码
import express from 'express'
const app = express()
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5500')
    next()
})
app.get('/info', (req, res) => {
    res.json({
        code: 200
    })
})
app.listen(3000, () => {
    // console.log('http://localhost:3000')
})

请求方法支持

我们服务端默认只支持 GET POST HEAD OPTIONS 请求

例如我们遵循restFul 要支持PATCH 或者其他请求

增加patch

js 复制代码
import express from 'express'
const app = express()
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5500')
    res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PATCH')
    next()
})
// app.get('/info', (req, res) => {
//     res.json({
//         code: 200
//     })
// })
app.patch('/info', (req, res) => {
    res.json({
        code: 200
    })
})
app.listen(3000, () => {
    console.log('http://localhost:3000')
})
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // fetch('http://localhost:3000/info').then(res=>{
        //     return res.json()
        // }).then(res=>{
        //     console.log(res)
        // })

         fetch('http://localhost:3000/info',{
            method:'PATCH',
        }).then(res=>{
            return res.json()
        }).then(res=>{
            console.log(res)
        })
    </script>
</body>
</html>

在请求头加上这行即可!

js 复制代码
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PATCH')

要注意app.js这个文件中要加上patch请求,html文件中请求也要加上patch请求

预检请求

js 复制代码
   fetch('http://localhost:3000/info',{
            method:'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({name: 'xmzs'})
        }).then(res=>{
            return res.json()
        }).then(res=>{
            console.log(res)
        })
js 复制代码
import express from 'express'
const app = express()
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5500')
    res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PATCH')
   // res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
    next()
})
// app.get('/info', (req, res) => {
//     res.json({
//         code: 200
//     })
// })
app.post('/info', (req, res) => {
    try {
        // 处理请求
        res.json({ code: 200 })
    } catch (error) {
        res.status(500).json({ code: 500, message: error.message })
    }
})
app.listen(3000, () => {
    console.log('http://localhost:3000')
})

发现报错了!!

因为 application/json 不属于cors 范畴需要手动支持

res.setHeader('Access-Control-Allow-Headers', 'Content-Type')

解决办法:去掉以上这行注释即可!

自定义响应头

在我们做需求的时候,可能会碰到后端自定义响应头

业务场景:传递"元数据"而非数据体

最常见的情况。后端返回了JSON/XML数据体,但想把数据体之外的状态信息(比如分页、签名)也传给前端。

  • 分页信息 :返回列表数据时,把 X-Total-Count(总条数)、X-Page(当前页)放在响应头,而不是塞进JSON体里。这样前端分页组件可以直接从响应头读取,数据体保持干净。------这个放在响应头还是响应体里还是要看框架!!
  • 文件下载信息 :下载文件时,自定义 X-File-Name(原始文件名)或 X-File-Size,方便前端在下载进度条或保存对话框中显示。
  • 业务状态码 :有些架构不把业务错误码放在HTTP状态码(如200/500)里,而是在响应头自定义 X-Business-Code,专门表示"库存不足""积分不够"等业务异常,让前端统一拦截处理。

什么时候该用自定义响应头,而不是放Body里?

当这个字段是"请求级别的控制信息"时,放Header;当它是"业务数据本身"时,放Body。

比如,X-Total-Count 是对这批数据的描述(控制分页组件),不是数据本身,所以放Header。而"用户名""订单金额"是业务数据,放Body。

一个需要注意的坑

前端(尤其是浏览器中的JavaScript)只能读取部分响应头 。默认暴露的只有 Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma

如果你的自定义头是 X-Custom-Header,后端必须在响应头里加上:

http

makefile 复制代码
Access-Control-Expose-Headers: X-Custom-Header, X-Total-Count

否则前端 getResponseHeader('X-Custom-Header') 会拿不到值,这是跨域安全策略(CORS)的限制。

好了言归正传!!

js 复制代码
app.get('/info', (req, res) => {
    res.set('xmzs', '1')
    res.json({
        code: 200
    })
})

前端如何取呢?

js 复制代码
fetch('http://localhost:3000/info').then(res=>{
            const headers = res.headers
            console.log(headers.get('xmzs'))
            return res.json()
        }).then(res=>{
            console.log(res)
        })

发现是null 这是因为后端没有抛出该响应头所以后端需要增加抛出的一个字段

js 复制代码
app.get('/info', (req, res) => {
    res.set('xmzs', '1')
    res.setHeader('Access-Control-Expose-Headers', 'xmzs')
    res.json({
        code: 200
    })
})

这样就会返回1了!!

SSE技术

Server-Sent Events(SSE)是一种在客户端和服务器之间实现单向事件流的机制,允许服务器主动向客户端发送事件数据。在 SSE 中,可以使用自定义事件(Custom Events)来发送具有特定类型的事件数据。

webSocket属于全双工通讯,也就是前端可以给后端实时发送,后端也可以给前端实时发送,SSE属于单工通讯,后端可以给前端实时发送

  • express 增加该响应头text/event-stream就变成了sse event 事件名称 data 发送的数据
js 复制代码
app.get('/sse',(req,res)=>{
    res.setHeader('Content-Type', 'text/event-stream')
    res.status(200)
    setInterval(() => {
        res.write('event: test\n')
        res.write('data: ' + new Date().getTime() + '\n\n')
    }, 1000)
})

前端接受

js 复制代码
const sse = new EventSource('http://localhost:3000/sse')
sse.addEventListener('test', (event) => {
    console.log(event.data)
})
相关推荐
SamDeepThinking26 分钟前
里氏替换原则的盲区:为什么符合契约的List替换依然会失败?
后端·面试·程序员
码事漫谈33 分钟前
比尔·盖茨这次谈的不是模型,是账单
前端·后端
小林ixn37 分钟前
从零设计一个博客系统的数据库:表结构、索引与约束的实战思考
数据库·后端·mysql
那咋乎吧2 小时前
线程上下文切换和用户态进入内核态 linux内核都发生了什么
后端
YIAN2 小时前
NestJS 入门核心梳理:模块化架构、装饰器与依赖注入
后端·nestjs
唐青枫2 小时前
别只会 malloc:Zig Allocator、所有权与内存生命周期实战
后端
__zRainy__2 小时前
Node系列 · ORM:log4js 日志记录
node.js·log4j
风曳丷2 小时前
12|用 Attack Tree 和 Trace 固化证据
后端
江华森2 小时前
云原生从0到1:Kubernetes 工作负载实战——Deployment/Service/滚动更新/弹性伸缩
前端·后端