跨域资源共享(CORS)的工作原理主要涉及浏览器和服务器之间的一系列交互:
简单请求
- 请求类型判断:当浏览器发起一个跨域的HTTP请求时,首先会判断该请求是否为简单请求。简单请求需满足以下条件:
- 请求方法为GET、POST或HEAD。
- HTTP头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Modified、Content-Type,且Content-Type的值仅限于application/x-www-form-urlencoded、multipart/form-data、text/plain。
- 直接发送请求:如果是简单请求,浏览器会直接向目标服务器发送请求,同时在请求头中自动添加一个
Origin
字段,用于标识请求的源地址。 - 服务器响应:目标服务器收到请求后,会根据请求的资源和自身的配置来决定是否允许该跨域请求。如果允许,服务器会在响应头中添加
Access-Control-Allow-Origin
字段,其值为允许访问的源地址。如果该值为*
,则表示允许任何源访问;如果是具体的域名,则只有该域名下的请求才被允许。同时,服务器还可以根据需要添加Access-Control-Allow-Credentials
字段来控制是否允许发送和接收Cookie等凭证信息,以及Access-Control-Expose-Headers
字段来指定哪些额外的响应头可以被浏览器访问。 - 客户端处理:浏览器收到响应后,会检查响应头中的
Access-Control-Allow-Origin
字段。如果该字段的值与请求的源地址匹配或为*
,则表示跨域请求成功,浏览器会将响应数据交给JavaScript代码进行处理。否则,浏览器会拒绝该响应,并抛出跨域错误。
非简单请求
- 预检请求发送:如果浏览器发起的跨域请求不是简单请求,浏览器会先向目标服务器发送一个预检请求(OPTIONS)。预检请求的目的是询问服务器是否允许该跨域请求,预检请求中会包含一些特殊的请求头,如
Access-Control-Request-Method
用于指定实际请求的方法,Access-Control-Request-Headers
用于指定实际请求中会携带的自定义请求头。 - 服务器预检响应:目标服务器收到预检请求后,会根据请求的信息和自身的配置来决定是否允许该跨域请求。如果允许,服务器会在预检响应头中添加
Access-Control-Allow-Origin
字段,指定允许的源地址,同时还会添加Access-Control-Allow-Methods
字段,列出允许的请求方法,以及Access-Control-Allow-Headers
字段,列出允许的请求头。如果请求中包含了Access-Control-Request-Credentials
字段,且服务器允许发送凭证信息,服务器还需要在预检响应头中添加Access-Control-Allow-Credentials
字段,并设置为true
。 - 正式请求发送:浏览器收到预检响应后,如果响应头中的
Access-Control-Allow-Origin
等字段表明允许该跨域请求,浏览器会接着发起正式的跨域请求,该请求与简单请求的发送方式类似,但会携带预检请求中指定的请求方法和请求头。 - 服务器正式响应:目标服务器收到正式请求后,会按照正常的请求处理流程进行处理,并在响应头中添加相应的
Access-Control-Allow-Origin
等字段,然后将响应数据返回给浏览器。 - 客户端处理:浏览器收到正式响应后,同样会检查响应头中的
Access-Control-Allow-Origin
等字段,如果匹配成功,则将响应数据交给JavaScript代码进行处理;否则,拒绝该响应并抛出跨域错误。
带凭证的请求
- 客户端设置:如果跨域请求需要携带Cookie等凭证信息,客户端需要在
XMLHttpRequest
或fetch
等API中设置withCredentials
属性为true
。 - 服务器要求:对于带凭证的跨域请求,服务器必须在预检响应和正式响应的头信息中都添加
Access-Control-Allow-Credentials
字段,并设置为true
,否则浏览器会拒绝该响应。同时,服务器在设置Access-Control-Allow-Origin
字段时,不能使用*
,而必须指定具体的源地址,以确保安全性。
跨域资源共享(CORS)通过浏览器和服务器之间的这种交互机制,在保证安全性的前提下,实现了跨域资源的访问,使得不同源的网页能够合法地获取和共享服务器端的资源,为现代Web应用的开发提供了更大的灵活性和扩展性。