一步解决CORS(跨域)问题

本文最后更新于:3 年前

小张带您一步在服务器后端解决跨域问题ヾ(≧∇≦*)ゝ

deemoPID50418538bysishenfan.jpg

CORS原理

CORS全称Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源。

Origin表示本域,也就是浏览器当前页面的域。当JavaScript向外域(如sina.com)发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。

CORS示意图

假设本域是my.com,外域是sina.com,只要响应头Access-Control-Allow-Originhttp://my.com,或者是*,本次请求就可以成功。

可见,跨域能否成功,取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin,决定权始终在对方手中。

上面这种跨域请求,称之为“简单请求”。简单请求包括GET、HEAD和POST(POST的Content-Type类型 仅限application/x-www-form-urlencodedmultipart/form-datatext/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足90%的需求。

无论你是否需要用JavaScript通过CORS跨域请求资源,你都要了解CORS的原理。最新的浏览器全面支持HTML5。在引用外域资源时,除了JavaScript和CSS外,都要验证CORS。例如,当你引用了某个第三方CDN上的字体文件时:

1
2
3
4
5
/* CSS */
@font-face {
font-family: 'FontAwesome';
src: url('http://cdn.com/fonts/fontawesome.ttf') format('truetype');
}

如果该CDN服务商未正确设置Access-Control-Allow-Origin,那么浏览器无法加载字体资源。

对于PUT、DELETE以及其他类型如application/json的POST请求,在发送AJAX请求之前,浏览器会先发送一个OPTIONS请求(称为preflighted请求)到这个URL上,询问目标服务器是否接受:

1
2
3
4
OPTIONS /path/to/resource HTTP/1.1
Host: bar.com
Origin: http://my.com
Access-Control-Request-Method: POST

服务器必须响应并明确指出允许的Method:

1
2
3
4
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://my.com
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 86400

浏览器确认服务器响应的Access-Control-Allow-Methods头确实包含将要发送的AJAX请求的Method,才会继续发送AJAX,否则,抛出一个错误。

由于以POSTPUT方式传送JSON格式的数据在REST中很常见,所以要跨域正确处理POSTPUT请求,服务器端必须正确响应OPTIONS请求。

一步解决跨域问题

解决方式

在项目中创建 /config/WebMvcConfig.java 并复制以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
* @author Sept Zhang
* @create 2021-04-09 21:20
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8082")
//允许的主机和端口
.allowedHeaders("*")
.allowedMethods("*")
//添加允许的请求方法 get,post等
.maxAge(30*1000);
}
}

谁在搞事?

是它——浏览器的同源策略 。可能不好访问,所以我把大体内容摘录一下,方便大家查看学习。

1
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

啥时候发生?

1
如果两个 URL 的 protocol、port (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。

换一句话说,就是 协议端口主机 有一个不同,就会产生跨域问题。

咋还有特例?

Internet Explorer(IE) 的同源策略有两个主要的差异点:

  • 授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),则不受同源策略限制。
  • 端口:IE 未将端口号纳入到同源策略的检查中,因此 https://company.com:81/index.htmlhttps://company.com/index.html 属于同源并且不受任何限制。

这些差异点是不规范的,其它浏览器也未做出支持,但会助于开发基于window RT IE的应用程序。

吐槽:IE可不是人造革n(≧▽≦)n。

咋允许跨源访问

可以使用 CORS 来允许跨源访问。CORS 是 HTTP 的一部分,它允许服务端来指定哪些主机可以从这个服务端加载资源。

上方的代码就是使用的这个方法。

怎么区分

网站的开发者工具(F12)

报错信息举例:

msedge浏览器(新版)

image

chrome浏览器:

image

跨源网络访问

同源策略控制不同源之间的交互,例如在使用XMLHttpRequest`` 标签时则会受到同源策略的约束。这些交互通常分为三类:

  • 跨域写操作(Cross-origin writes)一般是被允许。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight
  • 跨域资源嵌入(Cross-origin embedding)一般是被允许(后面会举例说明)。
  • 跨域读操作(Cross-origin reads)一般是不被允许,*但常可以通过内嵌资源来巧妙的进行读取访问。例如,你可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法。

参考:

Web 开发技术文档

写BUG博主

bilibili-江南一点雨

廖雪峰的AJAX博客