【WEB】深入明白 CORS(跨域资源共享):原理、配置与常见问题 ...

打印 上一主题 下一主题

主题 1008|帖子 1008|积分 3024

引言

在当代 Web 开辟中,跨域哀求已经成为不可制止的一部门。浏览器的同源计谋(Same-Origin Policy)固然提供了基本的安全保障,但也限定了不同域之间的数据交互。为了弥补这一限定,CORS(Cross-Origin Resource Sharing,跨域资源共享)应运而生。CORS 是浏览器的一项安全机制,允许从一个域名(如前端页面的域)发起跨域哀求,从而访问其他域名(如后端 API)的资源。通过这一机制,Web 应用可以灵活地访问跨域的资源,同时确保用户数据的安全。
本文将详细介绍 CORS 的工作原理、涉及的 HTTP 头部、跨域哀求的不同范例以及如安在前后端开辟中正确配置 CORS,资助开辟者更好地明白和办理常见的跨域问题。
一、同源计谋(Same-Origin Policy)概述

1.1 同源计谋的定义

浏览器的同源计谋(Same-Origin Policy)是一种重要的安全机制,用于阻止不同源(域)之间的恶意操纵。根据同源计谋,网页中的脚本只能访问与其所在网页相同源的资源。源的定义包罗三个主要部门:


  • 协议(Scheme):如 http:// 或 https://;
  • 主机(Host):如 www.example.com 或 api.example.com;
  • 端口(Port):如 80 或 8080。
如果哀求的协议、主机名或端口号不同等,浏览器将视为跨域哀求,默认会阻止这样的访问。比方:


  • http://example.com 和 https://example.com 属于不同泉源(协议不同);
  • http://example.com 和 http://api.example.com 属于不同泉源(主机名不同);
  • http://example.com:80 和 http://example.com:8080 属于不同泉源(端口不同)。
1.2 同源计谋的作用

同源计谋的焦点目标是保护用户的数据隐私和安全,制止恶意网站通过脚本发起未经授权的哀求,从而窃取或篡改用户的数据。比方:


  • 一个恶意网站可能试图通过 JavaScript 脚本访问银行网站,获取用户的敏感信息如账户余额或信用卡号码。
  • 如果没有同源计谋的保护,网站之间的数据交换将可能面临被恶意操控的风险。
二、CORS 的引入与工作原理

由于同源计谋对跨域资源共享的限定,前端开辟中常常需要访问不同域的资源,好比从 www.example.com 向 api.example.com 哀求数据。为了可以或许安全、灵活地举行跨域通信,CORS(跨域资源共享)机制应运而生。
2.1 CORS(跨域资源共享)的基本概念

CORS(Cross-Origin Resource Sharing) 是一种机制,允许受限的资源在一个域(域A)上被另一个域(域B)哀求。CORS 通过在 HTTP 哀求中添加额外的头部信息来实现跨域通信,从而办理了浏览器的同源计谋限定。
同源计谋(Same-Origin Policy)
浏览器的同源计谋(Same-Origin Policy)是一种用于防止不同泉源的网页相互干扰的机制。它要求,网页中的脚本只能访问与它相同源的资源。换句话说,不同域名、协议或端口的资源访问会被浏览器默认阻止。
同源的定义:


  • 相同的协议(http:// 与 https://)
  • 相同的主机名(www.example.com 与 example.com)
  • 相同的端口号(80与8080)
如果协议、主机名或端口号不相同,则被视为跨域哀求。
CORS 的焦点头脑是,服务器通过在 HTTP 响应头中设置特定字段,来允许或拒绝跨域哀求。CORS 并不改变浏览器的同源计谋,而是通过配置来放脱期定。
2.2 简单哀求与预检哀求

根据哀求范例,CORS 分为两种情况:简单哀求预检哀求
2.2.1 简单哀求(Simple Requests)

简单哀求是指那些符合以下条件的跨域哀求:


  • 哀求方法是 GET、POST 或 HEAD;
  • 哀求头部只包含以下字段之一:Accept、Content-Type(只限 application/x-www-form-urlencoded、multipart/form-data 和 text/plain),Authorization 等常见字段。
对于这种哀求,浏览器会直接发送哀求到服务器,并且不发送预检哀求。
2.2.2 预检哀求(Preflight Request)

如果跨域哀求方法是 PUT、DELETE、PATCH,大概哀求中包含自定义的 HTTP 头部(如 X-Custom-Header),浏览器首先会发送一个 OPTIONS 哀求来询问服务器是否允许跨域哀求。该哀求被称为“预检哀求”。服务器需要在响应中包含允许跨域访问的标识,浏览器才会继续发送实际的哀求。
2.3 预检哀求流程

在举行跨域哀求时,浏览器通常会先发送一个预检哀求(OPTIONS 哀求)以确定服务器是否允许跨域访问。预检哀求的流程如下:

  • 浏览器发送 OPTIONS 哀求:浏览器向服务器发送一个 OPTIONS 哀求,询问服务器是否支持跨域哀求。
  • 服务器响应 CORS 头部信息:服务器根据哀求的内容,在响应头中添加 CORS 相干的字段,告知浏览器是否允许跨域哀求。
  • 判断是否允许跨域哀求:浏览器根据服务器返回的 CORS 头部信息,判断是否允许继续发送实际的跨域哀求。
  • 发送实际哀求或报错

    • 如果服务器允许,浏览器会继续发送实际哀求。
    • 如果服务器不允许,浏览器会拒绝哀求并抛出 CORS 错误。

     阐明

  • 浏览器发送 OPTIONS 哀求:浏览器首先发送一个 OPTIONS 哀求到服务器,以询问是否允许跨域哀求。
  • 服务器响应 CORS 头部信息:服务器在响应中包含 Access-Control-Allow-Origin 等 CORS 相干头部,告知浏览器是否允许跨域。
  • 判断是否允许跨域哀求

    • 如果服务器允许跨域,浏览器会发送实际哀求。
    • 如果服务器不允许,浏览器会拒绝哀求,并报出 CORS 错误。

  • 发送实际哀求或拒绝

    • 如果允许,浏览器继续发出实际哀求。
    • 如果不允许,浏览器会显示 CORS 错误。

  • 服务器响应实际哀求:如果跨域哀求被允许,服务器会正常响应实际哀求。
  • 浏览器处理并显示响应:浏览器接收并处理服务器返回的数据,最后展示给用户。
通过上述流程,浏览器可以或许确保服务器允许跨域哀求,从而安全地举行数据交换。
三、CORS 相干 HTTP 头部

CORS 主要依赖服务器端的 HTTP 头部来举行配置。以下是常见的 CORS 相干头部字段及其作用:


  • Access-Control-Allow-Origin:指定哪些源(域)可以访问资源。可以是单个源,大概是 *(允许所有源)。
  • Access-Control-Allow-Methods:指定允许的 HTTP 方法(如 GET, POST, PUT, DELETE 等)。
  • Access-Control-Allow-Headers:指定允许的哀求头字段。
  • Access-Control-Allow-Credentials:指示是否允许发送凭据(如 cookies)到跨域资源。
  • Access-Control-Expose-Headers:允许客户端访问特定的响应头。
  • Access-Control-Max-Age:指示预检哀求的有效期,即多少秒内无需再次发送预检哀求。
3.1 Access-Control-Allow-Origin



  • 作用:指定哪些源(域)可以访问该资源。可以是单个域名,也可以是 *,表示允许所有泉源。


    • 单个域名:Access-Control-Allow-Origin: https://www.example.com
    • 允许所有泉源:Access-Control-Allow-Origin: *

    • 如果允许的泉源是动态的,服务器可以根据哀求的 Origin 动态返回允许的域名。

3.2 Access-Control-Allow-Methods



  • 作用:指定允许的 HTTP 哀求方法。
  • 常见值:GET, POST, PUT, DELETE, PATCH
3.3 Access-Control-Allow-Headers



  • 作用:指定哪些哀求头字段可以包含在实际哀求中。比方,某些自定义哀求头,如 X-Custom-Header,需要通过这个字段允许。
  • 示例:Access-Control-Allow-Headers: Content-Type, X-Custom-Header
3.4 Access-Control-Allow-Credentials



  • 作用:指示是否允许发送凭据(如 cookies)。如果设置为 true,表示跨域哀求中可以发送 cookies。
  • :true 或 false。
  • 注意:当设置为 true 时,Access-Control-Allow-Origin 不能为 *,必须指定详细的域名。
3.5 Access-Control-Expose-Headers



  • 作用:允许浏览器访问指定的响应头。默认情况下,浏览器只会袒露某些尺度的响应头,利用该字段可以袒露其他自定义的头部。
  • 示例:Access-Control-Expose-Headers: X-Response-Time
3.6 Access-Control-Max-Age



  • 作用:指定预检哀求的有效期(单位为秒)。在此期间,浏览器不会再次发送预检哀求。
  • 示例:Access-Control-Max-Age: 3600 表示预检哀求的结果有效期为 1 小时。
四、跨域哀求的范例

4.1 简单哀求



  • GETPOSTHEAD 方法
  • 头部字段限定:只允许常见的头部字段,如 Accept、Content-Type、Authorization 等。
4.2 预检哀求



  • 如果哀求方法是 PUT、DELETE、PATCH,大概包含自定义头部字段,浏览器会先发送一个 OPTIONS 哀求(预检哀求)询问服务器是否允许跨域操纵。
五、处理跨域问题的常见方式

以下分别展示在前端、Node.js、Python 和 Go 中处理跨域哀求的代码示例,并对其举行详细阐明。
5.1 前端(JavaScript)处理 CORS

在前端代码中,通常通过设置 fetchXMLHttpRequest 的 mode、credentials 等选项来控制跨域行为。
5.1.1 利用 fetch 发起跨域哀求

  1. fetch('https://example.com/data', {
  2.   method: 'GET',
  3.   headers: {
  4.     'Content-Type': 'application/json',
  5.   },
  6.   // 是否允许携带 cookies
  7.   credentials: 'include', // 'same-origin', 'include', 'omit'
  8. })
  9. .then(response => {
  10.   return response.json();
  11. })
  12. .then(data => {
  13.   console.log(data);
  14. })
  15. .catch(error => {
  16.   console.error('Error:', error);
  17. });
复制代码


  • credentials: 'include':允许携带 cookies。如果目标服务器配置了 CORS 头部 Access-Control-Allow-Credentials: true,浏览器才会发送带有 cookies 的跨域哀求。
5.1.2 利用 XMLHttpRequest 发起跨域哀求

  1. var xhr = new XMLHttpRequest();
  2. xhr.open('GET', 'https://example.com/data', true);
  3. xhr.withCredentials = true; // 设置是否带上凭证
  4. xhr.setRequestHeader('Content-Type', 'application/json');
  5. xhr.onreadystatechange = function() {
  6.   if (xhr.readyState == 4 && xhr.status == 200) {
  7.     console.log(JSON.parse(xhr.responseText));
  8.   }
  9. };
  10. xhr.send();
复制代码
5.2 Node.js 中处理 CORS

在 Node.js 中,处理 CORS 最常见的方式是利用 cors 中心件,它能简化 CORS 相干的配置。
5.2.1 利用 cors 中心件

首先,需要安装 cors:
  1. npm install cors
复制代码
然后在代码中引入并利用它:
  1. const express = require('express');
  2. const cors = require('cors');
  3. const app = express();
  4. // 使用 cors 中间件
  5. app.use(cors({
  6.   origin: 'https://your-frontend-domain.com', // 允许的来源
  7.   methods: ['GET', 'POST', 'PUT', 'DELETE'],
  8.   allowedHeaders: ['Content-Type', 'Authorization'],
  9.   credentials: true // 允许携带凭证
  10. }));
  11. app.get('/data', (req, res) => {
  12.   res.json({ message: 'Hello World' });
  13. });
  14. app.listen(3000, () => {
  15.   console.log('Server running on port 3000');
  16. });
复制代码
5.2.2 利用自定义 CORS 头部

如果不利用 cors 中心件,可以手动添加 CORS 头部:
  1. const express = require('express');
  2. const app = express();
  3. app.use((req, res, next) => {
  4.   res.header('Access-Control-Allow-Origin', 'https://your-frontend-domain.com'); // 允许的源
  5.   res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  6.   res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  7.   res.header('Access-Control-Allow-Credentials', 'true');
  8.   next();
  9. });
  10. app.get('/data', (req, res) => {
  11.   res.json({ message: 'Hello World' });
  12. });
  13. app.listen(3000, () => {
  14.   console.log('Server running on port 3000');
  15. });
复制代码
5.3 Python 中处理 CORS

在 Python 中,可以利用 Flask-CORS 扩展来处理 CORS。
5.3.1 安装 Flask-CORS

  1. pip install flask-cors
复制代码
5.3.2 配置 CORS

  1. from flask import Flask
  2. from flask_cors import CORS
  3. app = Flask(__name__)
  4. CORS(app, origins="https://your-frontend-domain.com", supports_credentials=True)
  5. @app.route("/data")
  6. def data():
  7.     return {"message": "Hello World"}
  8. if __name__ == "__main__":
  9.     app.run(port=5000)
复制代码
5.4 Go 语言中处理 CORS

在 Go 中,可以通过 gorilla/handlers 或 net/http 来处理 CORS。
5.4.1 利用 gorilla/handlers

首先安装 gorilla/handlers:
  1. go get github.com/gorilla/handlers
复制代码
然后配置 CORS:
  1. package main
  2. import (
  3.         "fmt"
  4.         "github.com/gorilla/mux"
  5.         "github.com/gorilla/handlers"
  6.         "net/http"
  7. )
  8. func main() {
  9.         r := mux.NewRouter()
  10.         r.HandleFunc("/data", func(w http.ResponseWriter, r *http.Request) {
  11.                 w.Write([]byte(`{"message": "Hello World"}`))
  12.         }).Methods("GET")
  13.         // 配置 CORS
  14.         headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"})
  15.         originsOk := handlers.AllowedOrigins([]string{"https://your-frontend-domain.com"})
  16.         methodsOk := handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE"})
  17.         // 启动服务器
  18.         http.ListenAndServe(":3000", handlers.CORS(originsOk, headersOk, methodsOk)(r))
  19. }
复制代码
六、CORS 处理流程图

     解释


  • 前端哀求资源:前端应用(比方一个网页)发出哀求,可能会向不同的域、协议或端口哀求资源,导致跨域。
  • 浏览器发送哀求:浏览器会发起 HTTP 哀求,向服务器哀求所需资源。
  • 浏览器检测是否跨域:浏览器根据哀求的目标 URL 判断哀求是否跨域。如果目标 URL 与当前网页 URL 的域、协议或端口不同,则认为是跨域哀求。
  • 是否跨域:这是判断跨域哀求与否的关键节点。如果哀求和当前页面的源不同,则会触发 CORS 机制。

    • 是跨域:浏览器会发送一个预检哀求(Preflight Request)。这是一个 HTTP 哀求,用于询问目标服务器是否允许跨域访问,通常是一个 OPTIONS 哀求。
    • 否跨域:如果哀求没有跨域,浏览器会直接发送哀求,不颠末预检过程。

  • 发送预检哀求(OPTIONS):如果是跨域哀求,浏览器会先发送一个 OPTIONS 哀求,询问服务器是否允许跨域操纵。
  • 服务器检查预检哀求并返回 CORS 响应头:服务器收到预检哀求后,会根据 CORS 配置返回相应的 CORS 头部信息,如 Access-Control-Allow-Origin 和其他相干字段。如果服务器允许该哀求,浏览器继续发送实际的哀求。
  • 服务器处理哀求并返回数据:如果预检哀求成功,浏览器会发出实际的跨域哀求。服务器处理哀求并返回数据。
  • 浏览器继承响应:浏览器接收到响应后,会检查 CORS 头部,确认是否允许访问资源。如果允许,则举行页面渲染;如果不允许,则阻止该哀求。
  • 渲染页面:如果响应没有问题,浏览器会将数据渲染到页面上,展示给用户。
  • 浏览器反馈 CORS 错误:如果预检哀求失败,大概响应头中缺少必要的 CORS 信息,浏览器会终止哀求并提示 CORS 错误。
七、CORS 常见问题

7.1 Access-Control-Allow-Origin 设置问题

No ‘Access-Control-Allow-Origin’ header is present on the requested resource:表示响应中缺少 Access-Control-Allow-Origin 头部。
描述
- Access-Control-Allow-Origin 是 CORS 头部中的关键字段,用来指定允许跨域访问的泉源(即允许哪些域名访问资源)。如果响应中没有该字段或该字段的值不匹配哀求的泉源,浏览器会阻止跨域哀求。报错为:
No ‘Access-Control-Allow-Origin’ header is present on the requested resource
办理方案


  • 服务器可以通过返回该头部来明白哪些域名被允许跨域访问。可以指定单一域名(如 https://example.com),大概利用通配符 * 允许所有域名访问,但通配符不能与带凭据的哀求(如 cookies 或 Authorization 头部)一起利用,也不能与 credentials: 'include' 一起利用。
  • 如果多个域名都需要访问,服务器可以动态判断哀求泉源,并根据泉源返回不同的 Access-Control-Allow-Origin 值。
示例
  1. Access-Control-Allow-Origin: https://example.com
复制代码


  • 如果允许所有域访问:
  1. Access-Control-Allow-Origin: *
复制代码
注意


  • 通配符 * 不能与带凭据的哀求(比方 cookies、Authorization)一起利用。如果哀求需要凭据,服务器必须指定明白的泉源(域名)。即 Access-Control-Allow-Origin 必须设置为明白的域名,而不能利用 *。
7.2. 预检哀求失败

描述


  • 对于某些复杂的哀求(如 PUT、DELETE,或包含自定义头部的哀求),浏览器会首先发送一个 OPTIONS 预检哀求,以确认服务器是否继承跨域哀求。如果服务器没有正确响应或缺少必需的 CORS 头部,实际哀求会被浏览器阻止。报错为:
    CORS policy: Response to preflight request doesn’t pass access control check
办理方案


  • 服务器需要正确处理 OPTIONS 哀求,并返回适当的 CORS 响应头。常见的响应头包罗:
  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods(指定允许的 HTTP 方法,如 GET, POST, PUT, DELETE 等)
  • Access-Control-Allow-Headers(列出允许的自定义头部)
示例
  1. Access-Control-Allow-Origin: *
  2. Access-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: Content-Type, Authorization
复制代码
7.3 带凭据的哀求问题

描述


  • 当浏览器在哀求中包含凭据(如 cookies 或 Authorization 头部)时,CORS 哀求需要显式的配置来允许凭据一起发送。如果服务器没有设置 Access-Control-Allow-Credentials,浏览器会拒绝携带凭据的哀求。可能出现以下错误:
    Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’
办理方案


  • 当浏览器携带凭据(如 cookies 或 Authorization)发起跨域哀求时,服务器需要在响应中设置 Access-Control-Allow-Credentials: true,并且 Access-Control-Allow-Origin 不能利用通配符(*),必须指定明白的域名。
示例
  1. Access-Control-Allow-Origin: https://example.com
  2. Access-Control-Allow-Credentials: true
复制代码


  • 如果服务器允许携带 cookies 和其他凭据,但未正确配置 Access-Control-Allow-Credentials,浏览器将拒绝哀求。
常见错误


  • No 'Access-Control-Allow-Origin' header is present on the requested resource:这通常意味着服务器没有正确设置 Access-Control-Allow-Origin 头部。
7.4 跨域哀求的缓存问题

描述


  • 浏览器可能会缓存跨域哀求的响应。如果 CORS 响应头设置不当,缓存可能导致不必要的跨域问题。
办理方案


  • 服务器可以通过设置 Cache-Control 头部,控制缓存计谋。比方,可以禁用缓存:
  1. Cache-Control: no-store
复制代码
示例
  1. Cache-Control: no-cache
  2. Access-Control-Allow-Origin: https://example.com
复制代码


  • 如果需要缓存响应,可以利用 no-cache,但仍需要确保正确设置 CORS 头部。
7.5 利用代明白决跨域

描述


  • 如果由于 CORS 设置问题而无法直接访问资源,可以通过设置一个代理服务器来转发哀求,从而绕过跨域限定。代理服务器会代表客户端发起哀求,并返回响应数据。
办理方案


  • 前端可以将哀求发送到与页面同域的代理服务器,由代理服务器向目标服务器发起哀求,再将响应返回给前端。
长处


  • 这种方式可以制止浏览器的 CORS 限定,但增加了额外的服务器端负担。
总结

CORS 是一种重要的浏览器安全机制,办理了不同源之间资源共享的问题。无论是在前端利用 fetch 或 XMLHttpRequest 发起哀求,还是在后端利用中心件或手动设置响应头部,正确的 CORS 配置对于确保跨域哀求的顺利举行至关重要。通过公道配置 CORS 相干头部,开辟者可以有效制止常见的跨域问题,如头部设置不正确、预检哀求失败、带凭据的哀求问题等。
掌握 CORS 的焦点原理与配置方法,不仅能资助开辟者顺利实现跨域资源共享,还能提高 Web 应用的安全性和用户体验。如果你在开辟过程中遇到任何 CORS 配置上的挑衅,随时可以寻求更多的资助和办理方案。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表