服务器允许跨域?允许跨域访问设置
如何解决跨域问题
仅为保存下来以便以后使用原文章:
跨域是指跨域名的访问,以下情况都属于跨域:
如果域名和端口都相同,但是请求路径不同,不属于跨域,如:
www.jd.com/item
www.jd.com/goods
跨域不一定会有跨域问题。
因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。
因此:跨域问题是针对ajax的一种限制。
但是这却给我们的开发带来了不变,而且在实际生成环境中,肯定会有很多台服务器之间交互,地址和端口都可能不同,怎么办?
目前比较常用的跨域解决方案有3种:
我们这里会采用cors的跨域方案。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出 XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
浏览器会将ajax请求分为两类,其处理方案略有差异:简单请求、特殊请求。
只要同时满足以下两大条件,就属于简单请求。:
(1)请求方法是以下三种方法之一:
(2)HTTP的头信息不超出以下几种字段:
当浏览器发现发现的ajax请求是简单请求时,会在请求头中携带一个字段: Origin.
Origin中会指出当前请求属于哪个域(协议+域名+端口)。服务会根据这个值决定是否允许其跨域。
如果服务器允许跨域,需要在返回的响应头中携带下面信息:
注意:
如果跨域请求要想操作cookie,需要满足3个条件:
不符合简单请求的条件,会被浏览器判定为特殊请求,,例如请求方式为PUT。
特殊请求会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest请求,否则就报错。
一个“预检”请求的样板:
与简单请求相比,除了Origin以外,多了两个头:
服务的收到预检请求,如果许可跨域,会发出响应:
除了 Access-Control-Allow-Origin和 Access-Control-Allow-Credentials以外,这里又额外多出3个头:
如果浏览器得到上述响应,则认定为可以跨域,后续就跟简单请求的处理是一样的了。
虽然原理比较复杂,但是前面说过:
事实上,SpringMVC已经帮我们写好了CORS的跨域过滤器:CorsFilter,内部已经实现了刚才所讲的判定逻辑,我们直接用就好了。
在 Application下编写一个配置类,并且注册CorsFilter:
结构:
放到Application下即可。
4.5.4.重启测试:
访问正常:
后端允许跨域怎么设置(后端配置允许跨域无效)
跨域的几种方法
浏览器出于安全方面的考虑,只允许客户端与本域(同协议、同域名、同端口,三者缺一不可)下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源,这被称为同源策略。
而有时候,我们不得不在一个客户端下访问不同域中的资源,于是需要用到一些方法来避开浏览器的同源策略,这些方法被称为跨域。
实现跨域有如下几种方法:
JSONP(JSONwithPadding)是数据格式JSON的一种使用模式,可以使网页实现跨域请求。其原理主要利用了HTML的script标签。由于script是采用开放策略,通过设置src引入不同域下的资源,所以可以通过script实现跨域,该方法需要后端支持。jsonp跨域的实现步骤如下:
下面来做个演示,首先为演示方便,将系统的hosts做如下修改:
以上例子最终实现了由example.a.com到example.b.com的跨域。应注意的是,因为script只能发送GET请求,所以jsonp只能实现GET请求的跨域。如果希望能实现其他请求的跨域,就可以用接下来介绍的一种方法——CORS。
CORS(全称为:Cross-OriginResouceSharing)跨域资源共享,是一种通过ajax跨域请求资源的方法。浏览器将CORS请求分为两大类,简单请求(simplerequest)和非简单请求(not-so-simplerequest,浏览器对这两种请求的处理方式不一样。如果请求满足以下两个条件,则为简单请求。
简单请求的实现方式即当用XMLHttpRequest发请求时,浏览器如果发现该请求不符合同源策略,会给该请求加上一个请求头origin,origin用来说明本次请求来自哪个源(协议+域名+端口)。如果origin指定的源不在后台允许范围内,后台会返回一个正常的HTTP响应,然后浏览器会发现该响应头部信息不包含Access-Control-Allow-Origin字段,然后抛出一个错误,该错误被XMLHttpRequest的onerror函数捕获,响应被驳回,但因为该错误无法通过状态码识别,所以HTTP回应的状态码还是200。如果origin在后台允许范围内,则服务器返回的响应,会包含Access-Control-Allow-Origin:Origin(指定的源)信息,浏览器此时不会抛错,响应能正常处理。
非简单请求是是请求方法为PUT或DELETE,又或者Content-Type为application/json的对服务器有特殊要求的请求。非简单请求的CORS请求,会在正式通信前增加一次HTTP查询,称为预检(preflight),询问服务器当前网页所在域名是否在服务器的许可名单中,如果在,则发出正式的XMLHttpRequest,之后就与简单请求一样,不在则报错。
依旧用上面的例子。
最终实现的效果与第一个jsonp的例子一样。
还有一种方式,就是通过降域来实现跨域。即通过设置document.domain的方式,将两个域名的domain设置为一个,如对于a.example.com和b.example.com,可以通过js设置document.domain="example.com",实现跨域。
做个演示,假设在下有一个a.html文件,其中a.html中有一个iframe,它的src为。
用降域方法实现跨域操作简单,但是有一些缺点。比如域名只能往下设置,不能回去,比如从example.com回到a.example.com。同时如果一个子域名被攻击,多个被降域的域名都会被连带攻击,有很大的安全风险。
postMessage是一个webAPI,可以实现跨域通信。window.postMessage()被调用时,会在所有页面脚本执行完毕后,向目标窗口派发一个MessageEvent消息。语法如下:
MessageEvent具有如下属性:
用一个与上面降域类似的例子来做演示。同样有两个页面a.html和b.html,a.html中的iframe的src指向b.html。
最终实现a.html与b.html通信效果如下:
使用postMessage方法应注意的是,如果不希望从其他网站接收message,那么不要为message事件添加任何监听器。如果确实希望接收其他网站的message,那么应该始终使用origin和source属性来验证发件人的身份,以免被恶意的网站攻击。
以上就是几种常见的跨域方法,各有优劣,且各自都有一定的安全问题,在日常应用中,需要有针对性的使用,对可能的安全风险采取相应措施。
前后端联调——跨域问题
19.7.24
前端通过http请求跨域的同时需要带上cookie信息,前端需要设置withCredentials=true。
而后端也需要有所修改。
Access-Control-Allow-Origin字段必须指定域名,不能为*
Access-Control-Allow-Credentials为true
后端可以通过HtttpServletRequest的Header中找到Origin。是跨域地址的host加port。
后端需要维护一个跨域URL的白名单,用Origincontains匹配白名单的URL,成功则配置response的Access-Control-Allow-Origin,指定Origin。
就实现跨域传cookie了。
参考:
什么是跨域、怎么解决跨域?
一个请求url的**协议、端口、域名**其中任意一个与当前页面url不相同就是跨域
即:?(http/https)协议、(segmentfault)主域名、(www)子域名、(8080)端口
是因为浏览器的同源策略的限制,同源策略是一种安全策略,同源指的是域名,协议,端口相同,会阻止一个域的js脚本和另一个域的内容进行交互。防止在一个浏览器中的两个页面产生不安全、异常的行为。
当然如果不同源的话会产生一定的限制:
【1】无法读取非同源网页的Cookie、LocalStorage和IndexedDB
【2】无法接触非同源网页的DOM
【3】无法向非同源地址发送AJAX请求
document.createElement(‘script’)生成一个script标签,然后插body里而已。
JSONP的实现原理就是创建一个script标签,再把需要请求的api地址放到src里.这个请求只能用GET方法,不可能是POST(向服务端传送数据)。
一种非正式传输协议,它会允许用户传递一个callback参数给服务端,然后服务端返回数据的时候会将这个callback参数作为函数名来包裹住JSON数据,然后客户端就可以随意的定义自己的函数来处理返回的数据了。
一般是后端在处理请求数据的时候,添加允许跨域的请求头信息,服务端设置Access-Control-Allow-Origin就可以,如果需要携带cookie,前后端都需要设置
window对象有个name的属性,在一个window下,窗口载入的页面都是共享一个window.name。
在a.html中,怎么把b.html页面加载进来,获取b.html的数据。在a.html页面使用iframe,可以去获取b.html的数据,然后在a.html页面中取得iframe获取得数据。
但是iframe想要获取b.html中的数据,只需要给这个iframe的src设为就可以,如果a.html想要得到iframe所获得的数据,也就是iframe的window.name的值,还要把这个iframe的src设成跟a.html页面同一个域才可以,不然a.html访问不到iframe里的window.name属性。
//父窗口打开一个子窗口
??varopenWindow=window.open('','title');
//父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
??openWindow.postMessage('Nicetomeetyou!','');
调用message事件,监听对方发送的消息
//监听message消息
??window.addEventListener('message',function(e){
??console.log(e.source);//e.source发送消息的窗口
??console.log(e.origin);//e.origin消息发向的网址
??console.log(e.data);?//e.data?发送的消息
??},false);
??server{
??#监听9099端口
??listen9099;
??#域名是localhost
??server_namelocalhost;
??#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址
??location^~/api{
????proxy_pass;
??}??
?}
//请求的时候直接用回前端这边的域名,这就不会跨域,然后Nginx监听到凡是localhost:9099/api这个样子的,都转发到真正的服务端地址
fetch('',{
?method:'POST',
?headers:{
??'Accept':'application/json',
??'Content-Type':'application/json'
?},
?body:JSON.stringify({
??msg:'helloIframePost'
?})
})
关于跨域的问题
一、在前端开发过程中,如果准备开发富应用,跨域的问题将会随之而来。
????????我们先看看什么是跨域呢:
????????所谓跨域,或者异源,是指主机名(域名)、协议、端口号只要有其一不同,就为不同的域(或源)。出于保护用户数据的目的,浏览器有一个最基本的策略就是同源策略,只允许页面内的脚本访问当前域的资源(加载脚本、资源等不受此限制)。
二、如果浏览器厂商不对跨域请求进行处理,会给我们带来什么危害呢?
????有心人士(病毒制造者)会利用这个漏洞进行如下攻击:
????1.CSRF/XSRF攻击,简单的来讲就是在b.com页面中请求a.com的接口(浏览器会自动带上用户在a.com的cookie),从而获取用户的在a.com的相关信息。
????2.XSS注入攻击,类似于SQL攻击,提交含有恶意脚本的数据到服务器,从而达到破坏页面或者获取用户的cookie。
三、我们了解到了什么是跨域,那我们又应该如何解决呢,现在找到了这些比较权威的文章,大家先品读一下:
????????1.mozilla官方网站关于跨域的文章(CrossOrigin),HTTP访问控制(CORS)
????????2.mozilla官方网站关于浏览器同源策略的简要介绍(SameOrigin),?浏览器的同源策略
四、读完这些文章,你打算怎么处理跨域问题呢,我先谈谈自己关于跨域的解决方案:
????????1.采用CORS协议,直接在Nginx中设置允许跨域的header(也可以在后端的应用程序内设置,不过在Nginx入口配置的话更加统一),在location配置中直接使用指令add_header(官方文档链接),示例配置如下:
????????2.使用JSONP,也是需要后端配合,利用“浏览器加载脚本、资源时不受同源策略的约束”这个特性,但是这种方式非常受限制,例如只能使用GET请求,不能携带自定义header等。
????3.其他的一些方法,例如window.name,document.domain以及HTML5中的特性window.postMessage等
五、其他参考链接
????1.?浅谈JS跨域问题
????2.跨域资源共享CORS详解----阮一峰
六、声明
????现在网络上的知识非常复杂,有些是摘自权威书籍的,有些是作者自己理解然后记录下来的,有些是瞎掰的,所以一定要结合情况多多甄别,对于有权威文档的知识点,建议先参考文档。
后端配置跨域
原文连接:原文地址
跨域的详细介绍可以参考:浏览器和服务器实现跨域(CORS)判定的原理,这里不多赘述。
1、主要就是客户端向发送了服务端请求,服务器已经能返回数据,但是浏览器不接收
2、在接口里面加上:(因为request是处理请求,response是返回结果)
response.setHeader("Access-Control-Allow-Origin",?"*");
response.setHeader("Cache-Control","no-cache");?
3、如果是使用SpringBoot创建的项目,直接添加一句注解到controller和方法就可以了:
@CrossOrigin
其中@CrossOrigin中的2个参数:
origins?:允许可访问的域列表
maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
在这个例子中,对于retrieve()和remove()处理方法都启用了跨域支持,还可以看到如何使用@CrossOrigin属性定制CORS配置。如果同时使用controller和方法级别的CORS配置,Spring将合并两个注释属性以创建合并的CORS配置。
4、如果您正在使用SpringSecurity,请确保在Spring安全级别启用CORS,并允许它利用SpringMVC级别定义的配置。
二、全局CORS配置
除了细粒度、基于注释的配置之外,您还可能需要定义一些全局CORS配置。这类似于使用筛选器,但可以声明为SpringMVC并结合细粒度@CrossOrigin配置。默认情况下,所有originsandGET,HEADandPOSTmethods是允许的。
JavaConfig
使整个应用程序的CORS简化为:
更多使用请看原文连接和官方文档
后端解决前端跨域请求问题
场景:前后端分离,页面和后端项目部署在不同服务器,出现请求跨域问题。
原因:CORS:跨来源资源共享(CORS)是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,是JSONP模式的现代版。与JSONP不同,CORS除了GET要求方法以外也支持其他的HTTP要求。用CORS可以让网页设计师用一般的XMLHttpRequest,这种方式的错误处理比JSONP要来的好,JSONP对于RESTful的API来说,发送POST/PUT/DELET请求将成为问题,不利于接口的统一。但另一方面,JSONP可以在不支持CORS的老旧浏览器上运作。不过现代的浏览器(IE10以上)基本都支持CORS。
预检请求(option):在CORS中,可以使用OPTIONS方法发起一个预检请求(一般都是浏览检测到请求跨域时,会自动发起),以检测实际请求是否可以被服务器所接受。预检请求报文中的Access-Control-Request-Method首部字段告知服务器实际请求所使用的HTTP方法;Access-Control-Request-Headers首部字段告知服务器实际请求所携带的自定义首部字段。服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。
解决方案:
1、创建一个过滤器,过滤options请求。
packagecom.biz.eisp.sci.util;
importorg.apache.commons.httpclient.HttpStatus;
importjavax.servlet.*;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.io.IOException;
/**
*解决跨域问题
*?
*/
publicclassCorsFilterimplementsFilter{//filter接口的自定义实现
??publicvoidinit(FilterConfigfilterConfig)throwsServletException{
}
@Override
??publicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{
HttpServletResponseresponse=(HttpServletResponse)servletResponse;
????HttpServletRequestrequest=(HttpServletRequest)servletRequest;
????response.setHeader("Access-Control-Allow-Origin","*");
????if("OPTIONS".equals(request.getMethod())){//这里通过判断请求的方法,判断此次是否是预检请求,如果是,立即返回一个204状态吗,标示,允许跨域;预检后,正式请求,这个方法参数就是我们设置的post了
??????response.setStatus(HttpStatus.SC_NO_CONTENT);//HttpStatus.SC_NO_CONTENT=204
??????response.setHeader("Access-Control-Allow-Methods","POST,GET,DELETE,OPTIONS,DELETE");//当判定为预检请求后,设定允许请求的方法
??????response.setHeader("Access-Control-Allow-Headers","Content-Type,x-requested-with");//当判定为预检请求后,设定允许请求的头部类型
??????response.addHeader("Access-Control-Max-Age","1");?//预检有效保持时间
????}
filterChain.doFilter(request,response);
??}
@Override
??publicvoiddestroy(){
}
}
2、修改web.xml文件
filter
?filter-namecors/filter-name
?filter-classcom.biz.eisp.sci.util.CorsFilter/filter-class
/filter
filter-mapping
filter-namecors/filter-name
?url-pattern/*?/url-pattern
/filter-mapping
3、spring-mvc.xml添加HttpRequestHandlerAdapter?http请求处理器适配器。
HttpRequestHandlerAdapter作为HTTP请求处理器适配器仅仅支持对HTTP请求处理器的适配。它简单的将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,它并不需要返回值。它主要应用在基于HTTP的远程调用的实现上。
beanclass="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/
使用nginx代理解决跨域问题
先说说跨域这事情吧。早在13年,我刚接触前端开发的时候就遇到了跨域,那时候刚开始流行前后端分离。解决跨域就是直接用get jsonp。还是小白的我,也没有去想跨域的其它解决方式和为什么要采用这种解决方式。
最近,做一个二次开发的项目,也碰到了用网页请求http post,浏览器跨域,不能获取返回数据的问题,所以再次来梳理下这个跨域,为什么最后选择了nginx代理。
首先,什么是跨域呢?首先需要了解的是同源和跨源的概念。对于相同源,其定义为:如果协议、端口(如果指定了一个)和主机对于两个页面是相同的,则两个页面具有相同的源。只要三者之一任意一点有不同,那么就为不同源。同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。当一个资源从与该资源本身所在的服务器的域或端口不同的域或不同的端口请求一个资源时,资源会发起一个跨域 HTTP请求。跨域不一定是浏览器限制了发起跨站请求,而也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。简单的来说,出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,即“同源策略”。而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果。
跨域的解决方案也有很多种。
类型一:有些浏览器可以设置,降低它的安全性。但是对于一个网站,要求设置浏览器是不切合实际的。
类型二:直接用form方式,这种情况下不是ajax请求,而是直接访问目标地址了,不存在跨域问题,但是这个页面已经跳转了。而我们想实现的只是取另外一个地址的数据到本地显示而已。
类型三:服务端语言是能够处理的情况下。
1、CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。跨域资源共享( CORS)机制允许 Web应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。其需要服务端和客户端同时支持。
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。 Access-Control-Allow-Origin该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。 Access-Control-Allow-Credentials该字段可选。 Access-Control-Expose-Headers该字段可选。
可以说这种办法主要在header上下功夫,设置Access-Control-Allow-Origin为所有*允许访问。虽然说它支持所有的请求方式,post,delete,put等等,但是它不能兼容ie6,7等等。
例如下图的nodejs express例子:
2、服务端的http ajax请求全部改为 get jsonp方式。该方式能够兼容老式浏览器。
3、iframe window.name这种传值得方式很巧妙,兼容性也很好。但是在要访问数据的地址那个服务器要有一个空的中间页面拿来用。
4、postMessage, html5 window.postMessage。同iframe window.name有点像,也是需要服务端有个空的html拿来接收数据。而且现在的postMessage兼容性也不好。
5、document.domain修改为顶级域名。
6、 WebSocket,协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
类型四:不是简单的前后端。假如有个第三方的api,自己有一个网站前端,一个网站后端。
1、自己的网站端和后端源码放在同一个服务端口和目录下,不存在跨域。当直接用网站前端的http访问第三方api,浏览器跨域。此时,改为由网站后端的服务端语言访问,做个中间人,将访问的数据给网页前端。
2、网站前端和后端不是同源的,采用以上的跨域方案,譬如CORS。同样的网站后端做中间人,访问第三方api,再转给网页前端。
3、使用nginx反向代理解决跨域问题。网站前端访问nginx服务的地址,nginx设置代理地址为访问第三方api地址,当访问代理地址的时候,浏览器访问的是nginx服务的地址,实际是访问第三方api地址。
注意:此时,如果目录下有个proxy.html,因为设置代理地址是/proxy,碰到这个地址就被转到”“,所以要访问proxy.html是访问不到的。
4、使用nginx代理地址是解决生产环境发布的问题了,那么我在开发的时候使用angular这样需要打包的框架怎么办呢。当然在开发环境下,angular也是由类似代理地址的解决方案的。
(1)创建配置代理文件:假设后端服务的访问地址为,我们可以创建一个proxy.conf.json文件,放在package.json同目录下。
(2)改写package.json文件,采用--proxy-config命令(angular自带的命令)。
(3)ajax访问代理地址
此时,执行 npm start,即可发现,浏览器访问的同源地址,实际上是访问.
angular在开发环境下代理地址的方法类似在生产环境下使用的nginx代理。但是测试angular是有一个/api代理地址的巧合。刚好第三方api上面的地址有个api,才能使用这个地址,并且能够简写一个api,才能成功访问,如果更改为其它的,譬如proxy,就测试失败。而且proxy.conf.json文件下的设置也只能是域名和端口。所以,本人测试,这或许是个巧合或者是缺陷。
五、其它
当然,跨域这个算是历史性的问题,以后也会存在这个问题。除了上面各种方法,以及根据各种方法使用的场合,还有许多其它的方法。例如各大流行框架react,vie应该也有像angular一样,能够处理跨域的开发环境方案,接下来,还是要继续学习和积累。