CORS跨域资源共享(一):模拟跨域请求以及结果分析,理解同源策略【享学Spring MVC】(中)

简介: CORS跨域资源共享(一):模拟跨域请求以及结果分析,理解同源策略【享学Spring MVC】(中)

请求成功案例


为了写出一个完全正确CORS简单请求,基于本例我只需要加一句代码即可:


@GetMapping("/test/cors")
public Object testCors(HttpServerResponse response) {
  // HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN
    response.addHeader("Access-Control-Allow-Origin", "http://localhost:63342");
    return "hello cors";
}


再次点击按钮发送ajax请求结果如下:


image.png


大功告成。服务端不仅仅正常处理了请求,浏览器也接受了返回值。


对于简单请求请务必杜绝这种case:返回的状态码是200(服务端逻辑正常执行且正常返回了),浏览器不会接收结果,而是回调到error方法去~


非简单请求


顾名思义,它比简单请求就要复杂些,不是简单请求的CORS请求都属于"非简单请求"(比如请求方法是PUT或DELETE)。它最大的一个特点是:在发送正式请求通信之前,增加一次HTTP OPTIONS请求,这个请求称之为预检(preflight)请求。


发送OPTIONS预检请求的过程完全由浏览器自动完成,开发者无需关心。


预检请求:它的作用是试探服务端是否能接受真正的请求,若服务器返回的状态码不是2xx而是4xx/5xx的话,那么浏览器将停止发送真正的请求。OPTIONS请求它具有如下特征:


  1. 没有请求body体
  2. 可以有响应body体(比如我们熟悉的:Invalid CORS request)
  3. 安全
  4. 幂等性
  5. 不能缓存,不能在表单里使用


下面先看一个非简单请求的例子,只需要把上例的Ajax注释的contentType放开即可,它便轻松成为了一个非简单请求了:

...
contentType: "application/json",
...


点击发送按钮,结果截图如下:


image.png


image.png


OPTIONS请求返回的状态码是403,所以真实的请求并未发送(network栏只有一个请求~)。浏览器自动添加的请求头中,最重要的仍然是Origin这个头,例如我们生产环境的请求头如下:


image.png


另外两个请求头解释如下(虽然不是十分重要,但也是必须了解的):


Access-Control-Request-Method:该请求头是必须的。发给服务器告知我接下来的真实方法是啥,本例是GET;

  • Access-Control-Request-Headers:非必须(因为可能无自定义的请求头嘛)。若有多个是逗号分隔,告诉服务器我真实请求即将携带的请求头是哪些,本例是content-type这一个请求头;
  • 这些请求头最终都发送给服务器,服务器收到这个预检请求后判断,检查这些头,确认允许跨域与否就可以做出相应的回应了(本例回应403:Forbidden)。


和非简单请求相关的5个响应头如下:


Access-Control-Allow-Origin和Access-Control-Allow-Credentials

同上


Access-Control-Allow-Methods


必须的相应头,值是逗号分隔的字符串。表明我服务器可以支持的所有跨域请求的方法~可以用*代替


注:为何返回的不单单是马上要发真实请求的那个方法,而是多个呢???这是为了避免多次"预检"请求,提高效率。后面你可以看到它的功效

Access-Control-Allow-Headers

若请求头中包含Access-Control-Request-Headers,那响应头中这个头就是必须的,否则是非必须的。它的值是逗号分隔的字符串,表示我服务器支持的所有头字段,不限于预检请求中的头字段(但请包含它~)。可以用*代替


说明:若请求头中有Access-Control-Request-Headers,但是没有此响应头/响应头中的值不包含请求头的值。那么出现的奇异现象便是:OPTIONS请求正常200返回,但是真实请求就不会发送了。所以使用时请务必注意~


Access-Control-Max-Age(重要)


非必须。它表示需要缓存预检结果多长时间,单位是秒。比如Access-Control-Max-Age: 600表示将预检结果缓存10分钟,即表示10分钟之内同样的URL将不再发送预检请求。如果值是0表示不用缓存~


Tips:因为它对url生效,所以对那些默认的查询条件取当前时间戳的可千万别这么干了,一般我相信你精确到日期就够了而不用精确到毫秒吧,否则age就不生效了(每次都还得发送预检请求)


当然,你的浏览器也是可以禁用掉这种缓存的。


image.png


请求成功案例


它和简单请求的处理方式是不一样的,因为OPTIONS请求进入不了Handler方法,所以在Controller里向HttpServletResponse里设置请求头是无效的。

因此我们应该把设置相应头信息放在Filter/HandlerInterceptor上才行,本例以Spring MVC的拦截器为例(生产上推荐使用Filter):


@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  // 这几个响应头都是可以用*来表示所有的
    response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
    response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "*");
    response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
    response.addHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "60");
    return true;
}


请注意:这些添加header只能放在preHandle,放在postHandle/afterCompletion里都将不生效(network里能看到这个头,但是无效果


配置好后,点击按钮发送Ajax请求,结果截图如下:


image.png


image.png


非简单请求跨域成功。从截图的结果上还能看到Access-Control-Max-Age它的功效,它能够减少OPTIONS请求的发送,从而减轻对服务端的访问压力。


如何理解Access-Control-Max-Age对相同URL生效???

为了更好理解这个响应头的作用,我针对性的做出如下试验:


为了测试,我把Access-Control-Max-Age设为了24小时,以保证缓存“永不过期”(控制变量法)



相关文章
|
人工智能 前端开发 JavaScript
webpack-dev-server代理后端一直报CORS跨域或500错误
在Vue项目中使用Webpack的devServer代理后端接口时,遇到500错误。问题根源在于浏览器请求中携带的Origin头导致服务器报错,而Postman测试正常。通过分析发现,调整或移除Origin头可解决问题。解决办法包括:1) 在代理配置中添加正确的Origin头;2) 删除请求中的Origin头。文章还深入解析了Origin头的作用及changeOrigin配置的实际意义,并附带相关文档链接,帮助开发者更好地理解与解决类似跨域问题。
1010 20
|
10月前
|
安全 API PHP
PHP中实现CORS跨域资源共享的方法
通过这种方式,你可以在PHP应用中灵活地实现CORS,以支持跨域Web应用的需求。
649 15
|
前端开发 JavaScript 应用服务中间件
前端跨域问题解决Access to XMLHttpRequest at xxx from has been blocked by CORS policy
跨域问题是前端开发中常见且棘手的问题,但通过理解CORS的工作原理并应用合适的解决方案,如服务器设置CORS头、使用JSONP、代理服务器、Nginx配置和浏览器插件,可以有效地解决这些问题。选择合适的方法可以确保应用的安全性和稳定性,并提升用户体验。
9657 90
|
JSON 缓存 前端开发
对CORS(跨域)的一些见解
CORS(跨域资源共享)是W3C标准,用于解决AJAX跨源请求限制。浏览器与服务器需共同支持CORS,浏览器自动处理请求头,开发者无需额外操作。CORS分为简单请求与非简单请求:简单请求满足特定条件(如方法为GET/POST/HEAD且头信息有限制),浏览器直接发送;非简单请求需先进行“预检”请求(OPTIONS方法),确认服务器允许后才发送实际请求。服务器回应需包含Access-Control-Allow-Origin等字段,以控制跨域访问权限。
421 10
|
安全 Java 应用服务中间件
SpringBoot:CORS是什么?SpringBoot如何解决跨域问题?
CORS是Web开发中常见且重要的机制,SpringBoot通过提供注解、全局配置和过滤器等多种方式来解决跨域问题。选择适合的方式可以帮助开发者轻松处理跨域请求,提高应用的灵活性和安全性。
891 2
CORS 跨域资源共享的实现原理是什么?
CORS 跨域资源共享的实现原理是什么?
|
安全
CORS 跨域资源共享的实现原理
CORS 跨域资源共享的实现原理
387 0
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1453 0
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1377 0
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
594 0