# 跨域 2024-07-17 ## 跨域的介绍 跨域请求(Cross-Origin Request)是指从一个域(Origin)向另一个域发起的HTTP请求。通常情况下,浏览器出于安全考虑,会阻止跨域请求,以防止潜在的跨站点脚本攻击(XSS)。这种安全策略称为同源策略(Same-Origin Policy)。 ### 什么是同源策略? 同源策略要求以下三个组成部分完全相同,才允许相互访问资源: 1. 协议(如http, https) 2. 域名(如example.com) 3. 端口号(如80, 443) 例如: - `http://example.com` 和 `http://example.com` 是同源的。 - `http://example.com` 和 `https://example.com` 不是同源的(协议不同)。 - `http://example.com` 和 `http://sub.example.com` 不是同源的(域名不同)。 - `http://example.com:80` 和 `http://example.com:8080` 不是同源的(端口不同)。 ### 跨域请求的场景 跨域请求通常在以下情况下出现: - 前端代码运行在`http://frontend.com`,需要访问`http://api.backend.com`的资源。 - 使用CDN资源(如字体、图片)时,CDN的域名与主站点的域名不同。 - 使用第三方服务的API(如支付网关、地图服务)。 ### 如何解决跨域请求问题? 为了允许合法的跨域请求,Web应用可以使用CORS(跨域资源共享,Cross-Origin Resource Sharing)来实现。CORS是一种机制,它通过设置HTTP头来告诉浏览器允许跨域资源请求。以下是一些常用的方法来实现CORS: #### 1. 设置CORS头 服务器可以通过在响应中设置`Access-Control-Allow-Origin`头来允许跨域请求。例如: ```http Access-Control-Allow-Origin: * ``` 或者指定特定的域: ```http Access-Control-Allow-Origin: http://allowed-origin.com ``` #### 2. 预检请求(Preflight Request) 对于某些复杂请求(如使用`PUT`、`DELETE`方法,或发送自定义头),浏览器会首先发送一个`OPTIONS`请求,这称为预检请求。服务器需要对预检请求进行响应,并设置相应的CORS头: ```http Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Allow-Origin: http://allowed-origin.com ``` #### 3. 使用代理服务器 如果不能修改目标服务器,可以通过设置代理服务器来解决跨域问题。前端请求发送到代理服务器,由代理服务器再转发请求到目标服务器,这样对于浏览器来说,所有请求都是同源的。 #### 4. JSONP(JSON with Padding) 在CORS普及之前,JSONP是一种常见的跨域解决方案。它通过动态创建` ``` 打开该HTML文件,在浏览器中点击“Fetch Data”按钮,如果服务器正确处理了跨域请求,你将看到响应数据。 ## 跨域请求的检测 跨域请求(Cross-Origin Request)的检测和限制主要由浏览器来执行,而不是由服务器来执行。这是因为浏览器实施了同源策略(Same-Origin Policy),它是一个重要的安全机制,旨在防止恶意网站通过脚本访问用户的敏感信息或执行恶意操作。 ### 同源策略(Same-Origin Policy) 同源策略要求在以下三个方面完全匹配才认为两个请求是同源的: 1. **协议(Protocol)**:例如`http`或`https`。 2. **域名(Domain)**:例如`example.com`。 3. **端口(Port)**:例如`80`或`443`。 如果两个请求在上述任何一个方面不匹配(即一个或多个部分不同),浏览器就会认为这是跨域请求,然后根据同源策略进行相应的限制。 ### 跨域请求的检测 当浏览器发现一个请求跨越了同源限制时,它会采取以下措施: 1. **阻止请求发送**:浏览器会阻止跨域请求的发送,不会向目标服务器发送实际的HTTP请求。 2. **不传递响应数据**:即使服务器返回了响应,浏览器也会阻止页面脚本访问响应数据,从而保护用户数据安全。 3. **预检请求(Preflight Request)**:对于某些复杂的跨域请求(如使用`PUT`、`DELETE`等方法或发送自定义头信息),浏览器会首先发送一个预检请求(`OPTIONS`请求),来询问服务器是否允许实际的请求。只有服务器返回了合适的CORS响应头,浏览器才会发送实际的请求。 ### 服务器的角色 虽然服务器不会直接执行跨域请求的检测和限制,但它可以通过设置响应头来告知浏览器如何处理跨域请求。服务器可以: - 设置`Access-Control-Allow-Origin`头来允许特定或所有来源的跨域请求。 - 设置`Access-Control-Allow-Methods`头来允许的HTTP方法。 - 设置`Access-Control-Allow-Headers`头来允许的自定义请求头。 - 处理预检请求(OPTIONS请求)并正确响应。 通过正确设置这些响应头,服务器可以与浏览器协作,使得合法的跨域请求能够顺利完成,从而实现跨域资源共享(CORS)。 ## 浏览器检测服务端是否支持跨域的步骤 当浏览器发送一个跨域请求时,它会进行一系列步骤来检测服务器是否支持跨域资源共享(CORS)。这些步骤主要涉及发送预检请求(OPTIONS请求)和检查服务器返回的响应头。以下是浏览器检测服务端是否支持跨域的详细步骤: ### 1. 发送跨域请求 浏览器中的JavaScript代码发起一个跨域请求,例如使用`fetch`、`XMLHttpRequest`等方法。 ### 2. 发送预检请求(OPTIONS请求) 如果满足以下条件之一,浏览器会首先发送一个预检请求(OPTIONS请求)到目标服务器: - 使用了非简单请求(例如使用了自定义头部信息)。 - 使用了不常见的HTTP方法(例如PUT、DELETE等)。 ### 3. 预检请求的内容 预检请求中的主要内容包括: - **请求方法(Method)**:通常为OPTIONS。 - **请求头部(Headers)**:包括发起请求时设置的自定义头部信息。 - **来源(Origin)**:指示请求的来源地址。 ### 4. 服务器处理预检请求 服务器接收到预检请求后,需要进行以下处理: - **验证请求来源(Origin)**:检查请求是否来自合法的来源。可以通过比对请求中的Origin字段与服务器允许的来源进行匹配来确认。 - **验证请求方法和头部信息**:检查请求是否使用了允许的HTTP方法(如GET、POST、PUT、DELETE等)和头部信息。 - **设置CORS响应头**:如果服务器支持跨域请求,需要设置适当的CORS响应头。主要包括: - `Access-Control-Allow-Origin`:指定允许访问的来源。可以设置为具体的来源或`*`表示允许所有来源。 - `Access-Control-Allow-Methods`:指定允许的HTTP方法。 - `Access-Control-Allow-Headers`:指定允许的自定义头部信息。 - `Access-Control-Allow-Credentials`:是否允许发送Cookie信息(如果请求中包含)。 ### 5. 浏览器处理预检请求响应 浏览器收到服务器的预检请求响应后,会进行以下处理: - **检查`Access-Control-Allow-Origin`头**:如果服务器返回了合法的`Access-Control-Allow-Origin`头(包括`*`通配符),浏览器认为跨域请求受到允许,继续发送实际请求。 - **检查其他CORS头部**:浏览器还会检查`Access-Control-Allow-Methods`、`Access-Control-Allow-Headers`等头部信息,确保服务器允许使用的HTTP方法和头部信息。 ### 6. 发送实际请求 如果预检请求的响应符合CORS规范要求,浏览器会继续发送实际的跨域请求(如GET、POST等),并将用户的Cookie等信息包含在请求中。 ### 7. 处理实际请求响应 最终,服务器接收并处理实际请求,并返回响应。浏览器在收到响应后,会根据同源策略(Same-Origin Policy)来决定是否允许页面脚本访问响应数据。 ### 总结 浏览器通过发送预检请求(OPTIONS请求)和检查服务器返回的CORS响应头来检测服务器是否支持跨域。服务器需要正确设置响应头,以允许合法的跨域请求。这种机制帮助确保跨域请求的安全性和合法性,防止恶意网站利用脚本攻击用户信息。 --- > 作者: [Hollis](https://www.xuexiqu.cn/) > URL: https://www.xuexiqu.cn/network/cross_domain/