No ‘Access-Control-Allow-Origin‘ header is present跨域及解决
作者:brucelwl 发布时间:2022-07-12 13:33:08
No ‘Access-Control-Allow-Origin‘ header is present
1 浏览器的限制
2 跨域
3 浏览器发送的是 XHR (XMLHttpRequest)请求
当以上三个条件都满足时浏览器会抛出跨域请求异常(记住是浏览器抛出的异常,和服务端没太大关系),在讲跨域请求解决方案前先了解几个问题。
http请求中,哪些是常见的简单请求,哪些是非简单请求
常见的简单请求:请求方法为:GET ,HEAD,POST,请求header里面无自定义头,Content-Type为以下几种:text/plain multipart/form-data application/x-www-form-urlencoded
常见的非简单请求 :请求方法为:put delete的ajax请求,发送json格式的ajax请求,带自定义头的ajax请求
浏览器在发送跨域请求时候,会有哪些过程
如果是简单请求,浏览器会先发送请求,然后判断服务器返的返回头中是否支持跨域请求,否则抛出跨域异常
如果是非简单请求,浏览器会先发出OPTIONS请求方法的检测命令,判断服务器是否支持跨域请求,如果支持则发送真正的请求,如果不支持则抛出跨域异常,因此一个非简单请求每次会发送两个请求,后面跨域解决方案会讲到缓存OPTIONS预检请求
跨域解决方案
方案1:禁用浏览器跨域校验,即允许跨域访问,(这种方案不可取,不可能让所有的浏览器设置允许跨域访问)
谷歌浏览器禁用跨域校验: 创建一个快捷方式发送到桌面 ,快捷方式--》右键---》属性页面中的目标输入框里追加 --disable-web-security --user-data-dir=C:\Program Files (x86)\Google\Chrome\Application (注意:--user-data-dir的值就是浏览器安装目录。)不一定生效
方案2:采用jsonp方式,需要后台和前台同时改动代码,
1 前台需要设置callback参数,如果使用的是jquery ajax 那么dateType属性设置为jsonp,jquery框架会自动设置参数名为callback的请求参数,也可以通过jsonp属性修改jsonp请求参数名,其他js框架根据具体api使用,
2 后台接收到callback参数后认为是jsonp请求,需要返回jsonp格式,普通json请求返回的content-Type是application/json,而jsonp返回的是application/javascript,同时也证明了jsonp请求服务端返回的是js脚本
3 jsonp请求参数名前后约定需要相同,例如jquery默认使用的是callback
弊端:jsonp 需要前后端都去修改代码,且jsonp是通过动态创建script脚本发送请求,仅支持 GET方法,jsonp发出的请求不是xhr请求,也是能解决跨域的原因
方案3:服务端解决跨域问题
通过编写filter在response对象中添加响应头,告诉浏览器允许跨域访问,* 号代码允许所有的请求域名,所有的请求方法跨域访问
@WebFilter("/*")
public class CORSFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
// 告诉浏览器允许所有的域访问
// 注意 * 不能满足带有cookie的访问,Origin 必须是全匹配
// resp.addHeader("Access-Control-Allow-Origin", "*");
// 解决办法通过获取Origin请求头来动态设置
String origin = request.getHeader("Origin");
if (StringUtils.hasText(origin)) {
resp.addHeader("Access-Control-Allow-Origin", origin);
}
// 允许带有cookie访问
resp.addHeader("Access-Control-Allow-Credentials", "true");
// 告诉浏览器允许跨域访问的方法
resp.addHeader("Access-Control-Allow-Methods", "*");
// 告诉浏览器允许带有Content-Type,header1,header2头的请求访问
// resp.addHeader("Access-Control-Allow-Headers", "Content-Type,header1,header2");
// 设置支持所有的自定义请求头
String headers = request.getHeader("Access-Control-Request-Headers");
if (StringUtils.hasText(headers)) {
resp.addHeader("Access-Control-Allow-Headers", headers);
}
// 告诉浏览器缓存OPTIONS预检请求1小时,避免非简单请求每次发送预检请求,提升性能
resp.addHeader("Access-Control-Max-Age", "3600");
chain.doFilter(request, resp);
}
}
方案4:Spring框架提供了跨域解决方案
spring提供了 @CrossOrigin注解用户解决跨域问题,同时支持全局配置
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}
方案5 服务端通过ngnix解决跨域问题
location /{
proxy_pass http://localhost:8080/;
#告诉浏览器允许跨域访问的方法
add_header Access-Control-Allow-Methods *;
# 告诉浏览器缓存OPTIONS预检请求1小时
add_header Access-Control-Max-Age 3600;
#允许带有cookie访问
add_header Access-Control-Allow-Credentials true;
#注意 * 不能满足带有cookie的访问,Origin 必须是全匹配,这里通过变量获取
add_header Access-Control-Allow-Origin $http_origin;
#设置支持所有的自定义请求头
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
#如果预检请求,则返回成功,不需要转发到后端
if ($request_method = OPTIONS){
return 200;
}
}
方案6 客户端通过nginx隐藏跨域
#转发全部以/api开头的请求到web服务器
location /api
{
proxy_pass http://127.0.0.1:8080/api;
}
来源:https://blog.csdn.net/u013202238/article/details/81605842


猜你喜欢
- instanceof关键字的使用1. 语法格式x instanceof A:检验x是否为类A的对象,返回值为boolean类型,如果是,返回
- 1.Overview经常研究.NET源码库的小伙伴会经常看到一个关键字volatile,那它在开发当中的作用是什么呢?我们一起来看看官方文档
- 因为线程重用导致的信息错乱的bugThreadLocal一般用于线程间的数据隔离,通过将数据缓存在ThreadLocal中,可以极大的提升性
- 方案一: 采用reflections 框架(此框架依赖com.google.guava)1、reflections框架地址:https://
- 目录概述代码实现完整代码概述在PC端用.NET开发一个蓝牙下载的程序。实现在PC上查找周围的蓝牙设备(主要是手机),并将PC上的文件通过蓝牙
- 要理解实现原理,必须把线程池的几个参数彻底搞懂,不要死记硬背一、线程池参数1、corePoolSize(必填):核心线程数。2、maximu
- 直接上代码:public class WeiXinFilter implements Filter{private static Logge
- 这几天自己研究了关于地手机上面开发安卓地图的问题,发现百度官方示例demo讲解百度持续定位方面还是讲解的有些不清楚,本人研究了几次之后将其弄
- 1.申请微信公众号我们要进行微信公众平台的开发,第一步当然是要有公众号了。什么?不知道什么是微信公众号,看来你还要先回炉炼炼了,呵呵。通俗的
- 一.并行LINQSystem.Linq名称空间中包含的类ParallelEnumerable可以分解查询的工作,使其分布在多个线程上。尽管E
- 目录功能使用类 SuperAdapter 的作用类 AbsViewHolder 的作用Sample这个适配器我珍藏已久(近两年), 不断看到
- C#事件标准命名规则一些开源代码的事件命名很混乱,以此文章用作本人以后工作的参考。事件的名称事件始终是指某个操作,这个操作可能正在发生,也可
- 一.服务器端获取Session对象依赖于客户端携带的Cookie中的JSESSIONID数据。如果用户把浏览器的隐私级别调到最高,这时浏览器
- 简介String是我们最常用的一个类,和普通java类一样其对象会存在java堆中。但是String类有其特殊之处,可以通过new方法生成,
- 1. 出故障了没办法,干it这一行,就得天天面对故障,大家就是传说中的消防员,到处救火。不过,这次的故障范围有点大,宿主机都打不开了。好在监
- 本文实例为大家分享了Android使用Retrofit上传文件的具体代码,供大家参考,具体内容如下一、封装RetrofitManagerpu
- 这篇文章主要介绍了java property配置文件管理工具框架过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- 项目开发中对于一些数据的处理需要用到多线程,比如文件的批量上传,数据库的分批写入,大文件的分段下载等。 通常会使用spring自带的线程池处
- 1、jdbc1) 含义:JDBC是java语言连接数据库,Java Date Base Connectivity2) jdbc的本质:在编程
- 这篇文章主要介绍了Java TreeSet类的简单理解和使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需