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

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

前言


CORS的全称是:跨域资源共享(Cross-origin resource sharing),它是浏览器的一个技术规范。

浏览器自己是可以发起跨域请求的(比如你可以外链一个外域的图片或者视频),但是Javascript脚本是不能跨域去获取这些资源的内容的。传统的ajax请求只能获取在同一个域名下的资源,但是Html5打破了这个限制:允许ajax发起跨域请求。跨域的解决方案有多种:JSONP、Flash、IFrame等,当然还有今天的主菜CORS。


我有理由相信若你在前端使用过Ajax,你100%遇见过如下图这样的报错


image.png


若你看到这样的报错,那么此次你的请求返回数据是失败的(请务必理解这句话)。但是,但是,但是若你查看调试工具的Network栏,发现这个URL请求的response是有返回值的(并且http状态码是200,表示请求被服务端正常处理了),形如这样:


image.png


image.png


看似相悖的结果,这到底怎么回事???本文就告诉你答案

同源策略


同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。该策略是浏览器最核心也最基本的安全功能,同源指的是:同协议、同域名、同端口。


它的核心思想可以理解为:我只相信我同一个域的资源,来自于其它域的我都不可信,所以同源策略主要还是出于安全考虑的~


JavaScript或Cookie只能访问同源(同协议、同域名、同端口下的内容。


CORS


CORS它是W3C(万维网联盟)的标准,它定义了在跨域访问资源时浏览器和服务器之间如何通信。它是为突破同源策略的限制而出现的一种官方标准的跨域解决方案。在实战场景中,跨域场景太为常见了(特别是当下前后端分离的开发模式),因此深入理解CORS变得就异常的重要了(反倒前端工程师不用太了解)。


若想实现CORS机制的跨域请求,是需要浏览器和服务器同时支持的。关于浏览器对CORS的支持情况:现在都9012年了,so可以认为100%的浏览器都是支持的,再加上CORS的整个过程都由浏览器自动完成,前端无需做任何设置,所以你的ajax原来怎么用现在还是怎么用,它对前段开发人员是完全透明的。

所以呢,让此种机制生效的关键就在于服务器端,so作为服务端开发的我们,必须要玩转CORS才可正常实现跨域通信。


CORS机制的指导思想:自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否


为何需要跨域请求???


这是跨域请求产生的背景,最主要是随着互联网的发展,忘了改善网络应用程序的环境增强其功能,开发人员要求浏览器供应商允许跨域请求,能带来如下好处:


  • javascript可以使用ajax方式跨域访问资源
  • CSS可以使用@font-face跨域调用字体
  • 通过canvas标签,绘制图表和视频


由此可见:跨域不仅仅是ajax的专属


本地模拟跨域请求以及结果分析


上面都是成套成套的理论知识,过于抽象。那接下来我就是要通过本地的实例来模拟出跨域请求,从而依托于案例分析CORS各种不同的case情况下的结果分析。


1、写一个前端HTML页面放于idea(idea可充当静态web服务器)


<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>CORS跨域</title>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<div style="text-align:center;margin-top: 100px;font-size: 60px;color: brown;cursor: pointer;">
    <span onclick="sendAjaxReq()">发送Ajax请求</span>
</div>
<script type="text/javascript">
    function sendAjaxReq() {
        $.ajax({
            type: "GET",
            // contentType: "application/json",
            url: "http://localhost:8080/demo_war_war/test/cors,
            success: function (message) {
                console.log("成功!" + message);
            },
            error: function (a, b, c) {
                console.log("失败!" + a.statusText);
            }
        });
    }
</script>
</body>
</html>


2、写一个控制器Controller处理页面发送的ajax请求


@RestController
public class CorsController {
    @GetMapping("/test/cors")
    public Object testCors() {
        return "hello cors";
    }
}


3、利用idea的web服务器能力运行html页面,如下截图(本例使用的是标准的63342静态web端口)


image.png


请注意这个页面的访问地址的是http://localhost:63342...,而点击这个"发送Ajax请求"按钮要发送的地址是http://localhost:8080...,两者端口号不一样说明是不同的域,因此此ajax请求它必定属于跨域请求(CORS请求)


4、点击发送按钮,查看控制台的结果

这个case的结果请完全参照文首的几张截图,此处就省略了


Tips:如果域名连不上服务端(比如服务端木有启动),它的报错一般都会是网络连接方面的问题,形如:GET http://localhost:8080/demo_war_war/test/cors net::ERR_CONNECTION_REFUSED,请注意区分~


如上结果,命名返回了200但浏览器偏偏还是报跨域异常,我相信这个让你感觉到十分的诧异和不解,那么接下来就围绕它来解释通这个问题。

但在我解释此现象之前,必须先要弄明白两个非常重要的CORS请求类型:简单请求,非简单请求(说明:这两种请求都属于CORS请求,这是大前提)。


简单请求、非简单请求


CORS发送出来的请求分为两种:


  1. 简单请求。需要同时满足下面三个要求1. 请求方法只能是GET、POST、HEAD2. Content-Type只能是三个值的任意一个application/x-www-form-urlencoded、multipart/form-data、text/plain(备注:若使用jquery的ajax发送请求,没指定Content-Type的情况下,默认它的值是application/x-www-form-urlencoded。源生的ajax请求请手动显示指定)3. 无自定义请求头(除了Accept、Content-Type等等一些内置的头之外的头都叫自定义)
  2. 非简单请求。除了简单请求之外都是它(带预检,也就是我们常见的OPTIONS请求)。


很显然,不满足简单请求三大要求的便都是非简单请求喽。在实际生产应用场景中我们最为常见的非简单请求场景大致有如下三种case:


  1. ajax发送put、delete请求
  2. 发送json格式数据(Content-Type为application/json)
  3. 自定义请求头(比如自定义鉴权请求头Authorization)


简单请求


对于这种请求,浏览器是直接发出请求,它的特点是:浏览器自动给加上一个Origin的请求头,表示这个请求的来源(来自哪个源)。

比如上面案例的请求,它完全符合简单的请求的三大要求,所以它是一个简单请求,浏览器自动给它加上的头是:Origin: http://localhost:63342。

服务端可拿到这个Origin源,然后判断服务端是否能够接受这个源从而决定是否同意这次请求(不同意or同意):


  • 不同意:服务器会返回一个正常的HTTP回应(响应头里木有Access-Control-Allow-Origin这个头),浏览器发现木有这个头,就抛出一个错误XMLHttpRequest,进而进入ajax的onerror回到方法里(这就是为何你明明看到http状态码是200,response也有返回值,但偏偏你ajax里就是进入的error的原因~),它的现象是:服务器正常返回了资源,但浏览器拒绝接收了。
  • 同意:服务器的响应里会多出下面详解的几个响应头,从而回调ajax的onsuccess方法,这就是真正意义上的成功了,浏览器也接收了这个返回结果。


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

Access-Control-Allow-Origin


该响应头是服务器必须返回的。它的值要么是请求时Origin的值(可从request里获取),要么是*这样浏览器才会接受服务器的返回结果。


Access-Control-Allow-Credentials

该响应头非必须,值是bool类型,表示是否允许发送Cookie


  • true:表示服务器允许你浏览器把cookie发给我(若服务器想获取Cookie的,请务必设置此值)
  • false :请注意此字段只能设置为true,若不允许发送cookie,不要设置此响应头即可

Tips:浏览器端默认情况下,Cookie不包括在CORS请求之中,若你想让浏览器带上Cookie,有需要的请自行研究一番吧~


Access-Control-Expose-Headers

该响应头非必须。顾名思义它要把response中的哪些头暴露给浏览器,让它可以获取到(默认情况下浏览器的XMLHttpRequest对象的getResponseHeader()方法只能获取到那些Cache-Control、Expires等等几个标准的响应头,若需要拿其它key,需要在这里指定)

相关文章
|
9月前
|
人工智能 前端开发 JavaScript
webpack-dev-server代理后端一直报CORS跨域或500错误
在Vue项目中使用Webpack的devServer代理后端接口时,遇到500错误。问题根源在于浏览器请求中携带的Origin头导致服务器报错,而Postman测试正常。通过分析发现,调整或移除Origin头可解决问题。解决办法包括:1) 在代理配置中添加正确的Origin头;2) 删除请求中的Origin头。文章还深入解析了Origin头的作用及changeOrigin配置的实际意义,并附带相关文档链接,帮助开发者更好地理解与解决类似跨域问题。
677 20
|
4月前
|
安全 API PHP
PHP中实现CORS跨域资源共享的方法
通过这种方式,你可以在PHP应用中灵活地实现CORS,以支持跨域Web应用的需求。
324 15
|
4月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
7月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
524 0
|
7月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
218 0
|
7月前
|
JSON 前端开发 Java
第05课:Spring Boot中的MVC支持
第05课:Spring Boot中的MVC支持
325 0
|
11月前
|
JSON 缓存 前端开发
对CORS(跨域)的一些见解
CORS(跨域资源共享)是W3C标准,用于解决AJAX跨源请求限制。浏览器与服务器需共同支持CORS,浏览器自动处理请求头,开发者无需额外操作。CORS分为简单请求与非简单请求:简单请求满足特定条件(如方法为GET/POST/HEAD且头信息有限制),浏览器直接发送;非简单请求需先进行“预检”请求(OPTIONS方法),确认服务器允许后才发送实际请求。服务器回应需包含Access-Control-Allow-Origin等字段,以控制跨域访问权限。
273 10
|
11月前
|
前端开发 JavaScript 应用服务中间件
前端跨域问题解决Access to XMLHttpRequest at xxx from has been blocked by CORS policy
跨域问题是前端开发中常见且棘手的问题,但通过理解CORS的工作原理并应用合适的解决方案,如服务器设置CORS头、使用JSONP、代理服务器、Nginx配置和浏览器插件,可以有效地解决这些问题。选择合适的方法可以确保应用的安全性和稳定性,并提升用户体验。
7729 90
|
JSON 安全 前端开发
浅析CORS跨域漏洞与JSONP劫持
浅析CORS跨域漏洞与JSONP劫持
816 3
|
开发框架 中间件 Java
如何处理跨域资源共享(CORS)的 OPTIONS 请求?
处理 CORS 的 OPTIONS 请求的关键是正确设置响应头,以告知浏览器是否允许跨域请求以及允许的具体条件。根据所使用的服务器端技术和框架,可以选择相应的方法来实现对 OPTIONS 请求的处理,从而确保跨域资源共享的正常进行。
792 61

热门文章

最新文章