Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Javascript跨域后台设置拦截

Javascript跨域后台设置拦截

作者头像
Ryan-Miao
发布于 2018-03-14 02:22:40
发布于 2018-03-14 02:22:40
1.1K00
代码可运行
举报
文章被收录于专栏:Ryan MiaoRyan Miao
运行总次数:0
代码可运行

子域名之间互相访问需要跨域

结论放在开头:

  1. 服务端必须设置允许跨域
  2. 客户端带cookie需要设置withCredentials
  3. 无论服务端是否允许跨域,该request都会完整执行
  4. options预请求需要设置返回空,不然requestMapping没有支持该方法则出错

环境搭建

需求

首先需要搭建两个环境。一个是提供API的server A,一个是需要跨域访问API的server B。

Server A提供了一个api。完整的请求request是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://local.corstest.com.net:8443/contentmain/getDepositsRoomAndRatePlanInfo.json?htid=759&_=1490855801818

Server B有个页面page:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
http://cros.corstest.com.net:3001/test.html

并且这个page需要请求server A的api。

但由于跨域保护,请求失败:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxxxx' is therefore not allowed access.

修改host

首先本地配置两个指向127.0.0.1的host,方便互相跨域。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
127.0.0.1   local.corstest.com.net 
127.0.0.1   cros.corstest.com.net

启动项目A,方便提供API。 至于项目B,测试跨域只要写个html静态页面即可。那么就写一个test.html,并通过一个工具发布:

browser-sync

安装

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install -g browser-sync

本地启动一个test.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
browser-sync start --server --files "*.html" --host "cros.corstest.com.net"  --port 3001

关于跨域CORS

ruanyifeng的文章里说浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

其中同时满足一下2种标准即为简单跨域:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1) 请求方法是以下三种方法之一:
HEAD
GET
POST
2HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

而其他情况,非简单请求是那种对服务器有特殊要求的请求,比如请求方法是 PUTDELETE,或者Content-Type字段的类型是application/json。非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight),即options请求。

关键

跨域的关键是浏览器获得服务器的认可,而服务器的认可就是header里的Access-Control-Allow-Origin。浏览器通过比较服务端返回的response中是否包含这个字段,以及包含这个字段的内容是否是当前网址来确定是否跨域。也就是说绕过浏览器是可以不用跨域的。

有个问题,看好多文章并没有指出。 第一点,带cookie问题。浏览器设置withCredentialstrue则会带cookie发送给服务端。而服务端设置Access-Control-Allow-Credentialstrue则接收,false则不接受。关键是到filter里的时候才会决定是否设置response,那么这时候cookie已经存在request里了吧。(待验证)

验证:server端确实已经接受了cookie,即使设置为false,服务端仍旧接受cookie。而客户端也仍旧可以发送cookie。

第二点,简单跨域中,浏览器的请求直接发送给服务器,服务器返回是否支持跨域(即是否header加origin), 那么简单跨域究竟是请求了服务端几次?如果是1次,那么如果服务端不支持跨域,即没有设置allow,还会不会继续走下去,会不会继续request得到结果后放入response?就是不论跨域不跨域服务器是否都会执行这个request对应的计算。因为所有的设置header都是给浏览器告知的,和服务端限制无关。(待验证)

验证:即使服务端没有设置允许跨域,当客户端请求过来时,服务端仍旧完整执行了请求并返回,只是客户端没有接收。

服务端需要做点工作

针对上述两种跨域。server A需要写一个filter。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<filter>
    <filter-name>cors</filter-name>
        <filter-class>com.test.filter.CorsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>cors</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</filter>

Filter:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CorsFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        URL requestURL = new URL(request.getRequestURL().toString());
        String hostName = requestURL.getHost();
        String origin = request.getHeader("Origin");

        int index = hostName.indexOf(".");

        if(index > -1) {
            String domainHost = hostName.substring(index, hostName.length());
            if(!StringUtils.isEmpty(origin) && origin.contains(domainHost)) {
                response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
                response.addHeader("Access-Control-Allow-Origin", origin);
                response.addHeader("Access-Control-Allow-Credentials", "true");
                response.setHeader("Access-Control-Max-Age", "3600");
                response.addHeader("Access-Control-Allow-Headers", "Content-Type, Cookie, " +
                        "Accept-Encoding, User-Agent, " +
                        "Host, Referer, " +
                        "X-Requested-With, Accept, " +
                        "Accept-Language, Cache-Control, Connection");

                if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
                    // CORS "pre-flight" request
                    response.setStatus(200);
                    return;
                }
            }
        }

        filterChain.doFilter(request, response);
    }
}

上述filter是为了同一个domain下,不同子域名可以跨域访问,而其他domain则不可以,因为我们需要共享cookie,所以设置Access-Control-Allow-Credentialstrue. 如果设置为false则不接受cookie。

客户端,即server B如果想要发送cookie则需要设置withCredentialstrue.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//原生
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
//jquery
$.ajax({
    ...
    xhrFields: {
        withCredentials: true
    }
    ...
}); 

注意,针对非简单跨域的时候发送options请求,服务端A需要告诉浏览器是否支持跨域即可,不要往下走了,不然到指定的requestMapping发现不支持这个方法就会很尴尬了,所以直接返回。

下面针对简单跨域和非简单跨域做测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">

    <meta charset="UTF-8">
    <title>test</title>

    <script src="jquery-1.11.3.js"></script>
</head>
<body>

<input type="button" value="GET_Default" onclick="testGetDefault()">
<input type="button" value="GET_JSON" onclick="testGetJSON()">
<input type="button" value="POST_Default" onclick="testPostDefault()">
<input type="button" value="POST_JSON" onclick="testPostJson()">
<input type="button" value="PUT" onclick="testPUT()">

<script>
    var getUrl = "https://local.corstest.com.net:8443/contentmain/getDepositsRoomAndRatePlanInfo.json?htid=759";
    var postUrl = "https://local.corstest.com.net:8443/contentmain/saveReservationDeposits.json?htid=759";

    function testGetDefault(){
        sendAjax("GET",getUrl, "json", "application/x-www-form-urlencoded");
    }
    function testGetJSON(){
        sendAjax("GET",getUrl, "json", "application/json; charset=utf-8");
    }
    function testPostDefault(){
        sendAjax("POST",postUrl, "json", "application/x-www-form-urlencoded");
    }

    function testPostJson(){
        sendAjax("POST",postUrl, "json", "application/json; charset=utf-8");
    }

    function testPUT(){
        sendAjax("PUT",postUrl, "json", "application/json; charset=utf-8");
    }

    
    function sendAjax(type, url, dataType, contentType){
        $.ajax( { 
            type: type,
            url:  url,
            xhrFields: {
                withCredentials: true
            },
            dataType : dataType, // accept type
            contentType: contentType,  //request type, default is application/x-www-form-urlencoded
            success: function(result){
                console.log(result);
            },
            error: function (xhr) {
                console.log(xhr);
            }
        });
    }


</script>
</body>
</html>
结果:

GET default: 只发送一个正常的get请求。

GET json:

先发送一个options如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
General:
Request URL:https://local.corstest.com.net:8443/contentmain/getDepositsRoomAndRatePlanInfo.json?htid=759
Request Method:OPTIONS
Status Code:200 OK
Remote Address:127.0.0.1:8443

Response Headers:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Cookie, Accept-Encoding, User-Agent, Host, Referer, X-Requested-With, Accept, Accept-Language, Cache-Control, Connection
Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin:http://cros.corstest.com.net:3001
Content-Length:0
Date:Thu, 30 Mar 2017 12:47:44 GMT
Server:Apache-Coyote/1.1

Request Headers:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:GET
Connection:keep-alive
Host:local.corstest.com.net:8443
Origin:http://cros.corstest.com.net:3001
Referer:http://cros.corstest.com.net:3001/test.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

然后再发送正常的Get请求。

post default: 正常发送请求。

post json: 先发送一个options请求。然后再发送正常的请求。 其他同理,总之,非简单跨域会多发一次options请求来确认是否支持跨域,这时候服务端一定要返回支持跨域,并且直接返回即可。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
安全系列之:跨域资源共享CORS
简介 什么是跨域资源共享呢? 我们知道一个域是由scheme、domain和port三部分来组成的,这三个部分可以唯一标记一个域,或者一个服务器请求的地址。跨域资源共享的意思就是服务器允许其他的域来访
程序那些事
2021/09/13
8980
跨域请求传递Cookie问题
前后端完全分离的项目,前端使用Vue + axios,后端使用SpringMVC,容器为Tomcat。 使用CORS协议解决跨域访问数据限制的问题,但是发现客户端的Ajax请求不会自动带上服务器返回的Cookie:JSESSIONID。 导致每一个Ajax请求在服务端看来都是一个新的请求,都会在服务端创建新的Session(在响应消息头中设置Set-Cookie:JSESSIONID=xxx)。 而在项目中使用了Shiro框架,用户认证信息是放在Session中的,由于客户端不会把JSESSIONID返回给服务器端,因此使用Session策略存放数据的方式不可用。
编程随笔
2019/09/11
3.6K0
跨域的解决方式(java后端)
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么Ajax就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。
Java微观世界
2025/01/21
4760
跨域的解决方式(java后端)
cookie跨域传输cookie问题:nginx跨域代理之proxy_cookie_domain
cookie作为辨别用户身份、进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),存储格式如下:
周陆军博客
2023/06/06
7.7K0
GIN框架解决跨域问题
当两个域具有相同的协议(如http), 相同的端口(如80),相同的host,那么我们就可以认为它们是相同的域(协议,域名,端口都必须相同)。
Porco1Rosso
2020/05/28
4.2K0
GIN框架解决跨域问题
Spring Boot 跨域解决方式
要解释跨域,先要了解同源策略,所谓同源策略就是在浏览器端出于安全考量,向服务端发起请求必须满足:协议相同、Host(ip)相同、端口相同,否则访问将被禁止,该访问也就被称为跨域访问。
数媒派
2022/12/01
6830
Web漏洞 | CORS跨域资源共享漏洞
有关于浏览器的同源策略和如何跨域获取资源,传送门 -->浏览器同源策略和跨域的实现方法
Gcow安全团队
2020/03/19
8.7K0
Web漏洞 | CORS跨域资源共享漏洞
CORS解决跨域问题
浏览器中,网站A的网络请求访问网站A的资源(图片,HTTP请求)是很顺畅的,而想访问网站B的资源,就要面对跨域资源访问的问题了。面对跨域问题,有很多的解决方案,本文讨论使用 CORS 来解决的方案。
张云飞Vir
2020/03/27
2.1K0
怎么解决跨域
存在浏览器同源策略,所以才会有跨域问题。那么浏览器是出于何种原因会有跨域的限制呢。其实不难想到,跨域限制主要的目的就是为了用户的上网安全。
程序员子龙
2024/04/30
2780
SpringBoot应用跨域访问解决方案
说到跨域访问,必须先解释一个名词:同源策略。所谓同源策略就是在浏览器端出于安全考量,向服务端发起请求必须满足:协议相同、Host(ip)相同、端口相同的条件,否则访问将被禁止,该访问也就被称为跨域访问。
字母哥博客
2020/09/23
1.2K0
SpringBoot应用跨域访问解决方案
再一次折腾跨域问题
跨域问题在前后端分离的开发场景中经常遇到,回想起来自己也已经折腾了数次,本篇文章主要对跨域问题做个记录和总结。
云原生
2022/03/30
5190
springmvc【问题1】跨域
简单的说即为浏览器限制访问A站点下的js代码对B站点下的url进行ajax请求。比如说,前端域名是www.abc.com,那么在当前环境中运行的js代码,出于安全考虑,访问www.xyz.com域名下的资源,是受到限制的。现代浏览器默认都会基于安全原因而阻止跨域的ajax请求,这是现代浏览器中必备的功能,但是往往给开发带来不便。特别是对我这样后台开发人员来讲,这个事情简直神奇。 但跨域的需求却一直都在,为了跨域,勤劳勇敢的程序猿们想出了许许多多的方法,例如,jsonP、代理文件等等。但这些做法增加了许多不必要的维护成本,而且应用场景也有许多限制,例如jsonP并非XHR,所以jsonP只能使用GET传递参数。更详细的资料可以看这里 Web应用跨域访问解决方案汇总
用户5640963
2019/07/26
9750
ajax跨域解决方案_java如何解决跨域问题
从刚接触前端开发起, 跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了,16年时也整理过一篇相关文章,但是感觉还是差了点什么,于是现在重新梳理了一下。
全栈程序员站长
2022/09/23
1.2K0
ajax跨域解决方案_java如何解决跨域问题
解决浏览器跨域限制方案之CORS
CORS是解决浏览器跨域限制的W3C标准,详见:https://www.w3.org/TR/cors/。 根据CORS标准的定义,在浏览器中访问跨域资源时,需要做如下实现:
编程随笔
2019/09/11
9090
解决浏览器跨域限制方案之CORS
CORS跨域资源共享(一):模拟跨域请求以及结果分析,理解同源策略【享学Spring MVC】
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
YourBatman
2019/09/25
5.3K0
CORS跨域资源共享(一):模拟跨域请求以及结果分析,理解同源策略【享学Spring MVC】
跨域共享CORS详解及Gin配置跨域
跨域简介 当两个域具有相同的协议(如http), 相同的端口(如80),相同的host,那么我们就可以认为它们是相同的域(协议,域名,端口都必须相同)。 跨域就指着协议,域名,端口不一致,出于安全考虑,跨域的资源之间是无法交互的(例如一般情况跨域的JavaScript无法交互,当然有很多解决跨域的方案) 解决跨域几种方案 /* CORS 普通跨域请求:只服务端设置Access-Control-Allow-Origin即可, 前端无须设置,若要带cookie请求:前后端都需要设置。
iginkgo18
2020/12/01
1.9K0
跨域二三事
更好的阅读体验 跨域是日常开发中经常开发中经常会接触到的一个重难点知识,何不总结实践一番,从此心中对之了无牵挂。 同源策略 之所以会出现跨域解决方案,是因为同源策略的限制。同源策略规定了如果两个 url 的协议、域名、端口中有任何一个不等,就认定它们跨源了。比如下列表格列出和 http://127.0.0.1:3000 比较的同源检测的结果, url 结果 原因 http://127.0.0.1:3000/index 同源 https://127.0.0.1:3000 跨源 协议不同
牧云云
2018/05/02
1.1K0
跨域二三事
JSONP、CORS解决跨域问题
是因为浏览器的同源策略是对ajax请求进行阻拦了,但是不是所有的请求都给做跨域,对href属性都不拦截。
用户1214487
2022/03/26
1.8K0
JSONP、CORS解决跨域问题
AJAX 与跨域通信(二):跨域解决方案
本篇讲解常见的几种跨域方案:JSONP、CORS、图像Ping、document.domain、window.name。
Chor
2019/11/11
1.5K0
AJAX 与跨域通信(二):跨域解决方案
跨域问题及CORS解决跨域问题方法
跨域不一定会有跨域问题。因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。
Java架构师必看
2021/03/22
13.1K0
相关推荐
安全系列之:跨域资源共享CORS
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验