跨域的解决方式(java后端)

文章目录

  • 一、跨域介绍
    • 1、什么是跨域
    • 2、为什么会产生跨域
  • 二、简单请求和非简单请求
    • 1、简单请求
    • 2、非简单请求
      • 2.1、预检请求
      • 2.2、预检请求的回应
      • 2.3、浏览器的正常请求和回应
  • 三、@CrossOrigin注解
    • 1、@CrossOrigin源码
    • 2、CorsRegistry方式
    • 3、CorsFilter过滤器
    • 4、自定义过滤器

一、跨域介绍

1、什么是跨域

  • 同源策略(Sameoriginpolicy)是浏览器最核心也最基本的安全功能
  • 一个页面发起的ajax请求,只能是与当前页域名相同的路径,这能有效的阻止跨站攻击
  • 所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号

2、为什么会产生跨域

  • 前后端分离模式下,客户端请求前端服务器获取视图资源
  • 客户端向后端服务器获取数据资源
  • 前端服务器的协议,IP和端口和后端服务器不一样,就产生了跨域

在这里插入图片描述

二、简单请求和非简单请求

  • CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)
  • 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制
  • 浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)

1、简单请求

只要同时满足以下两大条件,就属于简单请求

  • 请求方法是以下三种方法之一
    • HEAD
    • GET
    • POST
  • HTTP的头信息不超出以下几种字段
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限制三个值
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain

基本流程

  • 对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段

举例

  • 浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段
  • Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
  • 如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应
    • 浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文)
    • 从而抛出一个错误,但是这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200
  • 如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头

  1. Access-Control-Allow-Origin
    • 该字段是必须的
    • 要么是请求时Origin字段的值
    • 要么是一个*,表示接受任意域名的请求
  2. Access-Control-Allow-Credentials
    • 该字段可选
    • 它的值是一个布尔值,表示是否允许发送Cookie
    • 默认情况下,Cookie不包括在CORS请求之中
    • 设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器
    • 注意:如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名
  3. Access-Control-Expose-Headers
    • 该字段可选
    • CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma
    • 如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定
    • 上面的例子指定,可以返回FooBar字段的值

2、非简单请求

2.1、预检请求

  • 非简单请求是那种对服务器有特殊要求的请求
    • 比如请求方法是PUT或DELETE
    • 或者Content-Type字段的类型是application/json
  • 非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求
    • 浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段
    • 只有得到肯定答复,浏览器才会发出正式的请求,否则就报错

举例

  • HTTP请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header
  • 下面是这个"预检"请求的HTTP头信息
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
  • "预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源
  • Access-Control-Request-Method
    • 该字段是必须的
    • 用来列出浏览器的CORS请求会用到哪些HTTP方法
  • Access-Control-Request-Headers
    • 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段

2.2、预检请求的回应

服务器收到"预检"请求以后,检查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
  • 关键的是Access-Control-Allow-Origin字段
    • 表示http://api.bob.com可以请求数据
    • 该字段也可以设为星号,表示同意任意跨源请求
  • Access-Control-Allow-Methods
    • 该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法
    • 注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求
  • Access-Control-Allow-Credentials
    • 该字段与简单请求时的含义相同
  • Access-Control-Max-Age
    • 该字段可选,用来指定本次预检请求的有效期,单位为秒
    • 上面结果中,有效期是20天(1728000秒)
    • 在此期间,不用发出另一条预检请求

  • 如果服务器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段
  • 浏览器就会认定,服务器不同意预检请求
  • 控制台会打印出如下的报错信息

XMLHttpRequest cannot load http://api.alice.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

2.3、浏览器的正常请求和回应

  • 一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段
  • 服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段

"预检"请求之后,浏览器的正常CORS请求

  • 头信息的Origin字段是浏览器自动添加的
PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

服务器正常的回应

  • Access-Control-Allow-Origin字段是每次回应都必定包含的
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8

三、@CrossOrigin注解

1、@CrossOrigin源码

  • @CrossOrigin可以用在被RequestMapping修饰的方法Controller类上
  • 添加此注解即可实现跨域请求
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {@AliasFor("origins")String[] value() default {};@AliasFor("value")String[] origins() default {};/*** @since 5.3*/String[] originPatterns() default {};String[] allowedHeaders() default {};String[] exposedHeaders() default {};RequestMethod[] methods() default {};String allowCredentials() default "";long maxAge() default -1;
}

@CrossOrigin属性介绍

  • origins和value
    • 支持的源,origins和value都是相同的配置,互为别名,默认配置是“*”
    • 表示服务器支持所有源的跨域请求,安全信息较低
    • 最好根据实际情况设置对应的信息(协议 + 域名 + 端口)
  • originPatterns
    • 同样表示支持的源,Spring 5.3 引入的属性,默认为空
    • 与origins二选一,该字段为list,也就是可以配置多个
  • allowedHeaders
    • 允许跨域的请求头信息,默认为“*”表示允许所有的请求头
    • CORS默认支持的请求头为:Cache-Control、Content-Language、Expires、Last-Modified、Pragma
    • 如果你需要携带其他的请求头需要设置该属性
  • exposedHeaders
    • 服务器允许客户端访问的相应头,默认为空
    • 表示只允许访问:Cache-Control、Content-Language、Expires、Last-Modified、Pragm
    • 如果需要客户端访问其他的相应头需要设置该属性
  • methods
    • 服务器允许的Http Request类型,默认是允许GET、POST、HEAD
  • allowCredentials
    • 浏览器是否需要把凭证(如:cookies、CSRF tokens)发送到服务器,默认是关闭的
    • 该选项开启后会与配置的源建立高度信任的关系,并且还会暴露一些敏感信息,所以开启该选项时origin不允许设置为“*”
  • maxAge
    • “预检”结果的缓存时间,单位是秒
    • 默认1800s,在缓存时间内同一请求不需要“预检”请求

@CrossOrigin注解比较适用于较细粒度的跨域控制

2、CorsRegistry方式

@Configuration
//创建WebConfig类实现WebMvcConfigurer接口,通过CorsRegistry设置跨域信息
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/api/**").allowedOrigins("https://domain2.com").allowedMethods("PUT", "DELETE").allowedHeaders("header1", "header2", "header3").exposedHeaders("header1", "header2").allowCredentials(true).maxAge(3600);}
}

3、CorsFilter过滤器

在跨域过滤器里配置一下跨域头部,* 是通配符即允许所有

@Configuration
public class GatewayCorsConfiguation {@Beanpublic CorsFilter corsFilter(){// 初始化cors配置对象CorsConfiguration configuration = new CorsConfiguration();// 允许使用cookie,但是使用cookie是addAllowedOrigin必须是具体的地址,不能是*configuration.setAllowCredentials(true); 
//        configuration.addAllowedOrigin("*");configuration.addAllowedOrigin("http://manage.leyou.com");//允许的请求方式,get,put,post,deleteconfiguration.addAllowedMethod("*");  //允许的头信息configuration.addAllowedHeader("*");//初始化cors的源对象配置UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();corsConfigurationSource.registerCorsConfiguration("/**",configuration);//返回新的CorsFilter.return new CorsFilter(corsConfigurationSource);}
}

4、自定义过滤器

@WebFilter("/*")
public class CrosFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) servletResponse;HttpServletRequest request =(HttpServletRequest) servletRequest;response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");// 非预检请求,放行即可,预检请求,则到此结束,不需要放行if(!request.getMethod().equalsIgnoreCase("OPTIONS")){filterChain.doFilter(servletRequest, servletResponse);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/221545.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Knowledge Distillation from A Stronger Teacher(NeurIPS 2022)论文解读

paper:Knowledge Distillation from A Stronger Teacher official implementation:https://github.com/hunto/dist_kd 前言 知识蒸馏通过将教师的知识传递给学生来增强学生模型的性能,我们自然会想到,是否教师的性能越强&…

【操作系统导论】内存篇——分页

引入 采用 「分段」 的方式,将空间切成 不同长度的分片,会出现 碎片化 问题,随着时间推移,分配内存会越来越困难。 因此,值得考虑「分页」的方法: 将空间分割成 固定长度的分片 ; 将物理内存…

python列表的循环遍历

数据容器:一个可以存储多个元素的Python数据类型 有哪些数据容器:list(列表),tuple(元组),str(字符串),set(集合)&#x…

第三方电脑小爱同学用快捷键唤醒

第三方电脑安装小爱同学-CSDN博客 请结合之前安装小爱同学的教程安装过程请提前取消windows更新 安装完成之后登录账号即可使用 Ahk2.0 下载地址:https://www.autohotkey.com/download/ahk-v2.zip 打开链接即可自动下载,下载后解压出来点击install.cmd安…

微信公众服务号升级订阅号

服务号和订阅号有什么区别?服务号转为订阅号有哪些作用?首先我们要知道服务号和订阅号有什么区别。服务号侧重于对用户进行服务,每月可推送4次,每次最多8篇文章,发送的消息直接显示在好友列表中。订阅号更侧重于信息传…

java飞翔的鸟游戏

A.准备工作 Bird类 Column类 BirdGame类 Ground类 B.中间过程 准备工作: 安装Java开发环境(JDK)。选择一个集成开发环境(IDE),如Eclipse、IntelliJ IDEA或NetBeans。 创建项目: 在IDE中创建一个…

数据结构和算法(全)

1.了解数据结构和算法 1.1 二分查找 二分查找(Binary Search)是一种在有序数组中查找特定元素的搜索算法。它的基本思想是将数组分成两半,然后比较目标值与中间元素的大小关系,从而确定应该在左半部分还是右半部分继续查找。这个…

一文了解java中volatile关键字

认识volatile volatile关键字的作用有两个:变量修改对其他线程立即可见、禁止指令重排。 第二个作用我们后面再讲,先主要讲一下第一个作用。通俗点来说,就是我在一个线程对一个变量进行了修改,那么其他线程马上就可以知道我修改…

树莓派zero w入坑指南

树莓派zero w入坑指南 入坑契机 说起创客不得不提到开源硬件Raspberry Pi(树莓派)。它是一款基于ARM的微型电脑主板,以MicroSD卡为硬盘,提供HDMI和USB等外部接口,可连接显示器和键鼠。以上部件全部整合在一张仅比信用卡稍大的主板上&#x…

pytorch_lightning 安装

在安装pytorch-lightning时一定注意自己的torch是pip安装还是conda安装,pytorch_lightning 安装方式要与torch的安装方式保持一致,否则也会导致你的torch版本被替换。 正确安装方式: pip方式: pip install pytorch-lightning版本…

issue unit

The Issue Unit issue queue用来hold住,已经dispatched,但是还没有执行的uops; 当一条uop的所有的operands已经ready之后,request请求会被拉起来;然后issue select logic将会从request bit 1的slot中,选择…

第十二章 React 路由配置,路由参数获取

一、专栏介绍 🐶🐶 欢迎加入本专栏!本专栏将引领您快速上手React,让我们一起放弃放弃的念头,开始学习之旅吧!我们将从搭建React项目开始,逐步深入讲解最核心的hooks,以及React路由、…

0基础学java-day19(IO流)

一、文件 1 什么是文件 2.文件流 3.常用的文件操作 3.1 创建文件对象相关构造器和方法 package com.hspedu.file;import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test;import java.io.File; import java.io.IOException;/*** author 林然* vers…

js根据数组对象中的某个值去重

原理:利用对象key-value进行去重 去重方法: // 数组对象根据某一个值去重 filterList(list[], key) {let obj {};list?.forEach(item>{obj[item[key]]item;});return Object.values(obj); }, 用法: let list [{id: 1, name: 1},{id…

【TI毫米波雷达入门-11】毫米波速度相关计算

知识回顾 傅里叶变换 信号用复数表示,A :振幅, Q :相位 中频 信号 中频信号的相位 中频信号的表达公式 频率和相位的表达方式 使用两个Chirp 实现单个目标的测量 两个连续的chirp ,检测目标的相位差,通过速度和时间的关…

7+乳酸化+分型+实验,怎么贴合热点开展实验,这篇文章给你思路

今天给同学们分享一篇生信文章“Identification of lactylation related model to predict prognostic, tumor infiltrating immunocytes and response of immunotherapy in gastric cancer”,这篇文章发表在Front Immunol期刊上,影响因子为7.3。 结果解…

基于java的小型超市管理系统论文

摘 要 使用旧方法对超市信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在超市信息的管理上面可以解决许多信息管理上面的难题,比如处理数据时间很长,数据存在错误不能及时纠正等问题。 这次开发的小型超市管理系统有管理…

uniapp 数组添加不重复元素

一、效果图 二、代码 //点击事件rightBtn(sub, index) {console.log(sub, index)//uniapp 数组添加不重复元素if (this.selectList.includes(sub.type)) {this.selectList this.selectList.filter((item) > {return item ! sub.type;});} else {this.selectList.push(sub.t…

365锦鲤助手 砍价小程序源码 流量主引流裂变

源码介绍 修改版365锦鲤 助手, 砍价小程序源码 流量主引流裂变 拼多多商品快速丰富产品内容满足广大用户需求;流量矩阵让流量都进你的圈子飞起来;长期盈利、项目稳定 1.后台安装微擎 2安装应用 后台打包上传

23.12.10日总结

周总结 这周三的晚自习,学姐讲了一下git的合作开发,还有懒加载,防抖,节流 答辩的时候问了几个问题: 为什么在js中0.10.2!0.3? 在js中进行属性运算时,会出现0.10.20.300000000000000004js遵循IEEE754标…