Javascript实现跨域后台设置拦截的方法详解

本文主要给大家介绍了关于Javascript跨域后台设置拦截的相关内容,分享出来供大家参考学习,话不多说了,来一起看看详细的介绍吧。

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

结论放在开头:

1.服务端必须设置允许跨域

2.客户端带cookie需要设置 withCredentials

3.无论服务端是否允许跨域,该request都会完整执行

4. options 预请求需要设置返回空,不然requestMapping没有支持该方法则出错

环境搭建

需求

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

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

https://local.corstest.com.net:8443/contentmain/getDepositsRoomAndRatePlanInfo.json?htid=759&_=1490855801818

Server B有个页面page:

http://cros.corstest.com.net:3001/test.html

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

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

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,方便互相跨域。

127.0.0.1 local.corstest.com.net
127.0.0.1 cros.corstest.com.net

启动项目A,方便提供API。

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

 browser-sync 

安装

npm install -g browser-sync

本地启动一个test.html

browser-sync start --server --files "*.html" --host "cros.corstest.com.net" --port 3001

关于跨域CORS

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

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

1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

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

关键

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

有个问题,看好多文章并没有指出。

第一点,带cookie问题。浏览器设置 withCredentials 为 true 则会带cookie发送给服务端。而服务端设置 Access-Control-Allow-Credentials 为 true 则接收, false 则不接受。关键是到filter里的时候才会决定是否设置response,那么这时候cookie已经存在request里了吧。(待验证)

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

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

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

服务端需要做点工作

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

<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:

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-Credentials 为 true . 如果设置为 false 则不接受cookie。

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

//原生
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
//jquery
$.ajax({
 ...
 xhrFields: {
  withCredentials: true
 }
 ...
});

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

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

<!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如下:

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请求来确认是否支持跨域,这时候服务端一定要返回支持跨域,并且直接返回即可。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • JS跨域总结

    javascript跨域有两种情况: 1.基于同一父域的子域之间,如:a.c.com和b.c.com 2.基于不同的父域之间,如:www.a.com和www.b.com 3.端口的不同,如:www.a.com:8080和www.a.com:8088 4.协议不同,如:http://www.a.com和https://www.a.com 对于情况3和4,需要通过后台proxy来解决,具体方式如下: a.在发起方的域下创建proxy程序 b.发起方的js调用本域下的proxy程序 c.proxy将请

  • Javascript 跨域访问解决方案

    这里分两类情况:一.基于同一父域的子域之间页面的访问:参见如下3个domain域:taobao.com.jipiao.taobao.com.promotion.taobao.com:它们有相同的父域taobao.com.二.基于不同父域页面之间的访问:参见如下3个domain域:taobao.com.baidu.com.sina.com.cn:它们具有不同的父域. 解决它们之间跨域的方案有:方案1:服务器Proxy域A的页面JS需要访问域B下的链接获取数据,该方案在域A的服务器端建立一个Prox

  • AJAX javascript的跨域访问执行

    突然感觉就是这里的问题,研究一下,搞定后其实觉得挺容易的,只是自己知识还是有些欠缺,解决方法如下: 阻塞的AJAX请求 我们先来证实一下请求的阻塞情况吧.我们使用如下的代码: 连续发起三个请求  复制代码 代码如下: function simpleRequest()  {     var request = new XMLHttpRequest();      request.open("POST", "Script.ashx");      request.sen

  • js跨域请求数据的3种常用的方法

    由于js同源策略的影响,当在某一域名下请求其他域名,或者同一域名,不同端口下的url时,就会变成不被允许的跨域请求. 那这个时候通常怎么解决呢,对此菜鸟光头我稍作了整理: 1.JavaScript    在原生js(没有jQuery和ajax支持)的情况下,通常客户端代码是这样的(我假设是在localhost:8080的端口下的http://localhost:8080/webs/i.mediapower.mobi/wutao/index.html页面的body标签下面加入以下代码): <scr

  • 5种处理js跨域问题方法汇总

    前两天碰到一个跨域问题的处理,使用jsonp可以解决.(http://www.jb51.net/article/57889.htm) 最近再整理了一下: 1.jsonp. ajax请求,dataType为jsonp.这种形式需要请求在服务端调整为返回callback([json-object])的形式.如果服务端返回的是普通json对象.那么调试的时候,在chrome浏览器的控制台会报"Uncaught SyntaxError: Unexpected token"错误:在firefox

  • Javascript跨域请求的4种解决方式

    什么情况下才会出现跨域? 假设域名是:http://www.example.com.cn/ 如果所请求的域名跟这个域名不致,这种情况就是跨域,由于跨域存在漏洞,所以一般来说正常的跨域请求方式是请求不到的. 解决方式: 一.window.name 1. 服务器返回 复制代码 代码如下: <script>window.name='{"id":"3", "name":"leisure"}';</script>

  • Javascript实现跨域后台设置拦截的方法详解

    本文主要给大家介绍了关于Javascript跨域后台设置拦截的相关内容,分享出来供大家参考学习,话不多说了,来一起看看详细的介绍吧. 子域名之间互相访问需要跨域 结论放在开头: 1.服务端必须设置允许跨域 2.客户端带cookie需要设置 withCredentials 3.无论服务端是否允许跨域,该request都会完整执行 4. options 预请求需要设置返回空,不然requestMapping没有支持该方法则出错 环境搭建 需求 首先需要搭建两个环境.一个是提供API的server A

  • JavaScript实现生成动态表格和动态效果的方法详解

    今天上午完成了Vue实现一个表格的动态样式,那么JavaScript代码能不能实现同样的效果呢?这样也可以学习一下JavaScript的语法,晚上试了一下,完全可以,效果一模一样. <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="X-UA-Compatible" content="text/html; charset=utf-8">

  • JavaScript实现网页带动画返回顶部的方法详解

    服务器由阿里云换到了腾讯云,我的代码之前一直都是托管在git上的,但是搬家的时候,可能是着急了,之前有些新加的文件没有托管到git上,所以,就丢了. 不过无所谓了,可以重新写嘛. 之前博客的回到顶部功能是请之前的一位前端的同事帮忙写的,这次打算自己尝试一下. 返回顶部无非就是锚点. 第一个版本: <body style="height:2000px;"> <div id="topAnchor"></div> <a href=

  • JavaScript动画实例之粒子文本的实现方法详解

    1.粒子文本的实现原理 粒子文本的实现原理是:使用两张 canvas,一张是用户看不到的canvas1,用来绘制文本:另一张是用户看到的canvas2,用来根据canvas1中绘制的文本数据来生成粒子. 先在canvas1中用如下的语句绘制待显示的文本. ctx1.font = '100px PingFang SC'; ctx1.textAlign = 'center'; ctx1.baseline = 'middle'; ctx1.fillText('Happy New Year',canva

  • JavaScript中数组去重常用的五种方法详解

    目录 1.对象属性(indexof) 2.new Set(数组) 3.new Map() 4.filter() + indexof 5.reduce() + includes 补充 原数组 const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; 1.对象属性(indexof) 利用对象属性key排除重复项 遍历数组,每次判断新数组中是否存在该属性,不存在就存储在新数组中 并把数组元素作为key,最后返

  • Javascript获取图片原始宽度和高度的方法详解

    前言 网上关于利用Javascript获取图片原始宽度和高度的方法有很多,本文将再次给大家谈谈这个问题,或许会对一些人能有所帮助. 方法详解 页面中的img元素,想要获取它的原始尺寸,以宽度为例,可能首先想到的是元素的innerWidth属性,或者jQuery中的width()方法. 如下: <img id="img" src="1.jpg"> <script type="text/javascript"> var img

  • Nginx实现跨域使用字体文件的配置详解

    本文主要给大家介绍了关于Nginx跨域使用字体文件的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 问题描述 今天在使用子域名访问根域名的CSS时,发现字体无法显示,在确保CSS和Font字体的路径加载无问题后,基本确定是因为跨域的问题. 通过Nginx模块Http_Headers_Module来添加Access-Control-Allow-Origin允许的地址 console报错信息 ccess to Font at 'http://w001.static.akhack.com

  • php禁用函数设置及查看方法详解

    本文实例讲述了php禁用函数设置及查看方法.分享给大家供大家参考,具体如下: 打开PHP.INI,找到这行: disable_functions = 在后面那里加上要禁用的函数,如禁用多个函数,要用半角逗号 , 分开 给个例子: 复制代码 代码如下: disable_functions = passthru,exec,system,popen,chroot,scandir,chgrp,chown,escapesh ellcmd,escapeshellarg,shell_exec,proc_ope

  • JavaScript动态检测密码强度原理及实现方法详解

    本文实例讲述了JavaScript动态检测密码强度原理及实现方法.分享给大家供大家参考,具体如下: 在注册账户,设置密码时,会出现密码强度动态检测,网上看了一些帖子,大多只写了具体的实现过程,而没有对原理的分析过程.下面着重讲一下其原理. 原理分析 通常实现密码强度动态判断有两种方案实现: 正则.但其效率低一点,难度也大一些. 字符串,函数和运算符. 这里用第二种方案,但是如何判断一个密码串是强还是弱呢? 一般我们的密码会设置为数字.字母(大小写).特殊符号三类. 强:密码串包含其中三种或以上

  • JavaScript栈和队列相关操作与实现方法详解

    本文实例讲述了JavaScript栈和队列相关操作与实现方法.分享给大家供大家参考,具体如下: 一.栈的介绍 栈就是和列表类似的一种数据结构,数据只能在栈顶添加或者删除.栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,成为栈顶.栈具有后进先出的特点,所以任何不在栈顶的元素都无法访问. 后进先出(LIFO,last-in-first-out)的数据结构. 对栈的操作 1.对栈的两种主要操作为将一个元素压入栈和将一个元素弹出栈. 入栈:push(); 出栈:pop(); 2.预览栈顶的元素pe

随机推荐