CROS
CROS
介绍
CORS 是一个 W3C 标准,全称是跨源资源共享Cross-origin resource sharing,或者通俗地称为跨域资源共享。它允许浏览器向跨源的服务器,发出XMLHttpRequest请求,从而克服AJAX只能同源使用的限制。
什么是跨域
为了保证用户信息的安全,所有的浏览器都遵循同源策略。所谓同源是指协议+域名+端口三者都相同,有任何一个不同时,浏览器都视为非同源。此时跨域请求会被阻止。
当你向非同源的服务器发起网络请求的时候,这个请求就是跨域了。
举例:
http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略),dir/page.html是请求资源。它的同源情况:
http://www.example.com/dir2/other.html:同源(同一域名)http://example.com/dir/other.html:不同源(域名不同)http://v2.www.example.com/dir/other.html:不同源(域名不同)http://www.example.com:81/dir/other.html:不同源(端口不同)https://www.example.com/dir/page.html:不同源(协议不同)
注:我们在使用postman等工具模拟发起http请求的时候,不会遇到跨域的情况。
CORS的两个请求
简单请求
满足以下条件时,浏览器直接发送请求并检查响应头:
- 请求方法为
GET、POST、HEAD。 - 请求头仅包含
Accept、Accept-Language、Content-Language、Content-Type(且值为application/x-www-form-urlencoded、multipart/form-data或text/plain)。
服务器需返回Access-Control-Allow-Origin等头部授权访问。
非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。浏览器先发送OPTIONS请求验证服务器是否允许。若预检响应通过(如包含Access-Control-Allow-Methods),再发送实际请求。称为预检请求preflight。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
HTTP请求报文头部
1 | OPTIONS /cors HTTP/1.1 |
预检请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。
Origin
• 作用:由浏览器自动添加,表示请求的发起源(协议+域名+端口)。
• 示例:Origin: http://localhost:3000
• 触发条件:所有跨域请求均会携带此字段。Access-Control-Request-Method
• 作用:在预检请求(OPTIONS)中声明实际请求将使用的HTTP方法(如PUT、DELETE)。
• 示例:Access-Control-Request-Method: PUT
• 触发条件:非简单请求(如使用PUT/DELETE方法)的预检阶段。Access-Control-Request-Headers
• 作用:在预检请求中声明实际请求将携带的自定义请求头(如Authorization)。
• 示例:Access-Control-Request-Headers: Content-Type, Authorization
• 触发条件:请求包含自定义头或非简单Content-Type(如application/json)时触发预检。
HTTP响应报文头部
1 | HTTP/1.1 200 OK |
Access-Control-Allow-Origin- 作用:指定允许访问资源的源,值可为具体域名或通配符
*表示同意任意跨源请求。(带Cookie时不能为*)。 - 示例:
Access-Control-Allow-Origin: http://localhost:3000 - 必填性:所有CORS响应必须包含此字段。
- 作用:指定允许访问资源的源,值可为具体域名或通配符
Access-Control-Allow-Methods- 作用:声明服务器支持的跨域HTTP方法(如
GET, POST, PUT)。 - 示例:
Access-Control-Allow-Methods: GET, POST, PUT - 必填性:预检请求的响应中必须包含,避免多次预检。
- 作用:声明服务器支持的跨域HTTP方法(如
Access-Control-Allow-Headers- 作用:声明服务器允许的请求头字段(如
Content-Type、Authorization)。 - 示例:
Access-Control-Allow-Headers: Content-Type, Authorization - 必填性:当请求包含自定义头时,预检响应必须包含此字段。
- 作用:声明服务器允许的请求头字段(如
Access-Control-Allow-Credentials- 作用:指示是否允许浏览器携带Cookie等凭证,值为
true或false。 - 示例:
Access-Control-Allow-Credentials: true - 限制:需与前端
withCredentials: true配合使用,且Access-Control-Allow-Origin不能为*。
- 作用:指示是否允许浏览器携带Cookie等凭证,值为
Access-Control-Max-Age- 作用:指定预检请求结果的缓存时间(单位:秒),减少重复预检。
- 示例:
Access-Control-Max-Age: 86400(缓存24小时) - 推荐值:根据业务需求设置,避免过长导致策略更新延迟。
Access-Control-Expose-Headers- 作用:允许客户端通过
getResponseHeader()访问的响应头(默认仅限6个基础头)。 - 示例:
Access-Control-Expose-Headers: X-Custom-Header - 适用场景:需暴露自定义响应头时使用。
- 作用:允许客户端通过
如果服务器否定了预检请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。
1 | Access to XMLHttpRequest at 'http://localhost:8080/login' from origin 'http://localhost:5173' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response. |
一旦服务器通过了“预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
跨域请求的解决方案
C++ Crow库
1 | crow::App<crow::CORSHandler> app; |
正确的HTTP报文
HTTP请求报文头部
1 | HTTP/1.1 200 OK |
HTTP响应报文头部
1 | GET / HTTP/1.1 |

