ajax开发中的跨域

一、问题描述:

在某域名下使用Ajax向另一个域名下的页面请求数据,会遇到跨域问题。“已拦截跨源请求:同源策略禁止读取位于 xxxx 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。” 浏览器的console中会给出这样的错误提示信息。这源自于浏览器的同源策略。

同源策略是浏览器的一项最为基本同时也是必须遵守的安全策略,毫不夸张地说,浏览器的整个安全体系均建立在此之上。同源策略的存在,限制了“源”自A的脚本只能操作“同源”页面的DOM,“跨源”操作来源于B的页面将会被拒绝。所谓的“同源”,必须要求相应的URI在如下3个方面均是相同的。术语“源(Origin)”在中文表达中显得有点突兀,所以在接下来的内容中,我们更多地会采用“站点(Site)”或者“域(Domain)”这样的说法,在未作特别说明的情况下均与“源”表达相同的意思。

  • 主机名称(域名/子域名或者IP地址)
  • 端口号
  • 网络协议(Scheme,分别采用“http”和“https”协议的两个URI被视为不同源)
值得一提的是,对于一段JavaScript脚本来说,其“源”与它存储的地址无关,而 取决于脚本被加载的页面 。比如我们在某个页面中通过如下所示的<script>标签引用了来源于不同地方(“http://www.artech.com/”和“http://www.jinnan.me/”)的两个JavaScript脚本,它们均与当前页面同源。

 1: <script src="http://www.artech.com/scripts/common.js"></script>
 2: <script src="http://www.jinnan.me/scripts/utility.js"></script>

除了<script>标签,HTML还具有其它一些具有src属性的标签(比如<img>、<iframe>和<link>等),它们均具有跨域加载资源的能力,所以同源策略对它们不做限制。对于这些具有src属性的HTML标签来说,标签的每次加载都意味着针对目标地址的一次HTTP-GET请求。

同源策略以及跨域资源共享在大部分情况下针对的是Ajax请求。同源策略主要限制了通过XMLHttpRequest实现的Ajax请求,如果请求的是一个“异源”地址,浏览器将不允许读取返回的内容,我们可以通过一个简单的实例来演示这一点。

二、解决方案

最常见的两种方案:1. jsonp跨域请求. 2. CORS(Cross-Origin Resource Sharing)方案。

1. JSONP跨域请求方案:

1)请求type改成了get,JSONP只支持get请求,这个参数在JSONP场景下其实是可以忽略的,即使改成post,也会依然按get模式;

2) dataType改成了jsonp,这个参数标明要采用JSONP方式进行调用;

3)jsonp: “x5callback”,这个参数其实是一个约定的参数名,用于后端按照这个参数名获取一个回调函数名;

4)jsonpCallback:这个参数用来指定上面那个参数对应的回调函数名,如果不指定,jQuery会自动生成一个随机的函数名。

jsonp是一种非官方的解决跨域的方案。

2. CORS方案

这个方案实现起来非常简单,只需要在服务端返回的头部信息中增加:

response.setHeader("Access-Control-Allow-Origin","http://b.test.com")

三、跨域传递cookie

通过修改请求头是可以传递cookie等信息的。但是w3c的标准写的很清楚,cookie,connection和content-length等是不安全的字段,容易导致多种的request smuggling攻击,不允许编程设置。这些字段浏览器会自动帮你设置,如果设置就会报出错误:“Refused to set unsafe header "Content-Length"。
 既然ajax跨域中直接设置请求头是不允许的,那么我们就必须在ajax请求发出之前就应该设置cookie,然后ajax请求时会自动去填充请求头header内容(其中cookie内容会自动从硬盘中读取)。同时服务器端也要做些返回头的修改:

        response.setHeader("Access-Control-Allow-Credentials","true");

对于JQuery,前端ajax请求可以设置如下:
    document.cookie=“pin=test;domain=test.com;”;
    $.ajax({
       url:_url,
       type:"get",
       data:"",
        dataType:"json",
       xhrFields: {
          withCredentials: true
       },
       crossDomain: true,
对于Angular,可以设置如下:
$http({
    method: 'get',
    url: getBookList,
    withCredentials: true,
    data: {s: $scope.smartTablePageSize, i: 1},
}).then(function successCallback(response) {
    console.log(response);
}, function errorCallback(response) {
    console.log(response);
});
但是我们可能还会遇到另外一个问题,浏览器对每一个跨域请求,会在正式请求之前加上一个OPTIONS请求,
因为这个请求是浏览器自己加上的,所以是不会带上cookies的,我们也无法控制。而如果服务器端不做任何
处理,对于需要回话保持的请求,这个请求会报错(no session)。

三、OPTIONS请求

OPTIONS方法是用于请求获得由Request-URI标识的资源在请求/响应的通信过程中可以使用的功能选项。通过这个方法,客户端可以在采取具体资源请求之前,决定对该资源采取何种必要措施,或者了解服务器的性能。

该请求方法的响应不能缓存。

如果这个OPTIONS请求包含一个正文(有Content-Length或Transfer-Encoding存在),则必须有Content-Type来指定媒体类型。虽然规范里没有定义这种正文的用法,但是HTTP将来的扩展可能会用它来查询服务器上更详细的信息。不支持该扩展的服务器可以忽略该请求正文。

如果该URI是一个星号(“*”),OPTIONS请求将试图应用于服务器,而不是某个指定资源。由于服务器的通信选项通常依赖于资源,所以此“*”请求只能作为“ping”或者“no-op”方法;或者用来测试服务器的性能。例如,用来测试HTTP/1.1代理。

如果该URI不是星号,则只能用来获取该资源通信中可用的选项。

得到的200响应应该包含一个头域,指明服务器实现的和适用于该资源的可选特征(如:Allow),可能还包括该规范尚未定义的扩展。如果有响应正文,则应包含关于通信选项的信息。本规范没有定义该正文格式,但可能在HTTO将来的扩展中定义。可以利用内容协商来选择合适的响应格式。如果没有响应正文,响应必须包含Content-Length,并且值为“0”。

请求头的Max-Forwards用来请求特定代理。当代理收到一个允许URI转发的OPTIONS请求,则检查Max-Forwards。如果Max-Forwards值为0,则不能转发该消息;相反,代理会将自己的通信选项去响应。如果Max-Forwards是正整数,代理转发请求的时候会将该值减1。如果请求中没有Max-Forwards,转发的请求也不会有。

OPTIONS请求方法的主要用途有两个:

1、获取服务器支持的HTTP请求方法;也是黑客经常使用的方法。

2、用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。

所以,服务器端要针对跨域的OPTIOS做特殊的处理,放过对他的session校验,这样它后面的真正的请求才能被发送。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值