响应头

HTTP响应头(HTTP response headers)是在HTTP响应中发送的元数据信息,用于描述响应的特性、内容和行为。它们以键值对的形式出现,每个键值对由一个标头字段(header field)和一个相应的值组成。

例如以下示例

Access-Control-Allow-Origin:*
Cache-Control:public, max-age=0, must-revalidate
Content-Type:text/html; charset=utf-8
Server:nginx
Date:Mon, 08 Jan 2024 18:32:47 GMT

响应头和跨域之间的关系

  • cors

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

  • 发送请求
fetch('http://localhost:3000/info').then(res=>{
    return res.json()
}).then(res=>{
    console.log(res)
})
  • express 编写一个get接口
import express from 'express'
const app = express()
app.get('/info', (req, res) => {
    res.json({
        code: 200
    })
})
app.listen(3000, () => {
    console.log('http://localhost:3000')
})

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

Nodejs 第三十一章(响应头和请求头)_响应头

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

Access-Control-Allow-Origin: * | Origin

增加以下响应头 允许localhost 5500 访问

app.use('*',(req,res,next)=>{
    res.setHeader('Access-Control-Allow-Origin','http://localhost:5500') //允许localhost 5500 访问
    next()
})

结果返回

Nodejs 第三十一章(响应头和请求头)_响应头_02

请求头

默认情况下cors仅支持客户端向服务器发送如下九个请求头

tips 没有application/json

  1. Accept:指定客户端能够处理的内容类型。
  2. Accept-Language:指定客户端偏好的自然语言。
  3. Content-Language:指定请求或响应实体的自然语言。
  4. Content-Type:指定请求或响应实体的媒体类型。
  5. DNT (Do Not Track):指示客户端不希望被跟踪。
  6. Origin:指示请求的源(协议、域名和端口)。
  7. User-Agent:包含发起请求的用户代理的信息。
  8. Referer:指示当前请求的源 URL。
  9. Content-type: application/x-www-form-urlencoded | multipart/form-data | text/plain

如果客户端需要支持额外的请求那么我们需要在客户端支持

'Access-Control-Allow-Headers','Content-Type' //支持application/json

请求方法支持

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

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

增加patch

app.patch('/info', (req, res) => {
    res.json({
        code: 200
    })
})

发送patch

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

发现报错说patch不在我们的methods里面

Nodejs 第三十一章(响应头和请求头)_json_03

修改如下

'Access-Control-Allow-Methods','POST,GET,OPTIONS,DELETE,PATCH'

Nodejs 第三十一章(响应头和请求头)_前端_04

预检请求 OPTIONS

预检请求的主要目的是确保跨域请求的安全性 它需要满足一定条件才会触发

  1. 自定义请求方法:当使用非简单请求方法(Simple Request Methods)时,例如 PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH 等,浏览器会发送预检请求。
  2. 自定义请求头部字段:当请求包含自定义的头部字段时,浏览器会发送预检请求。自定义头部字段是指不属于简单请求头部字段列表的字段,例如 Content-Type 为 application/json、Authorization 等。
  3. 带凭证的请求:当请求需要在跨域环境下发送和接收凭证(例如包含 cookies、HTTP 认证等凭证信息)时,浏览器会发送预检请求。
  • 尝试发送预检请求
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)
})
  • express
app.post('/info', (req, res) => {
    res.json({
        code: 200
    })
})

发现报错了

Nodejs 第三十一章(响应头和请求头)_express_05

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

'Access-Control-Allow-Headers','Content-Type'

Nodejs 第三十一章(响应头和请求头)_express_06

Nodejs 第三十一章(响应头和请求头)_node.js_07

自定义响应头

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

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

Nodejs 第三十一章(响应头和请求头)_express_08

前端如何读取呢?

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 这是因为后端没有抛出该响应头所以后端需要增加抛出的一个字段

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

Nodejs 第三十一章(响应头和请求头)_前端_09

SSE技术

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

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

  • express
    增加该响应头text/event-stream就变成了sse
    event 事件名称 data 发送的数据
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)
})

前端接受

const sse = new EventSource('http://localhost:3000/sse')
sse.addEventListener('test', (event) => {
    console.log(event.data)
})

Nodejs 第三十一章(响应头和请求头)_前端_10