zoukankan      html  css  js  c++  java
  • 处理Ajax请求跨域问题

    ajax跨域的原理

    ajax出现请求跨域错误问题,主要原因就是因为浏览器的“同源策略”。

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

    基本上目前所有的浏览器都实现了CORS标准,其实目前几乎所有的浏览器ajax请求都是基于CORS机制。

    浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求。

    • 请求方法是以下三种方法之一:HEAD,GET,POST
    • HTTP的头信息不超出以下几种字段:

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

    凡是不同时满足上面两个条件,就属于非简单请求

     跨域示例:

    出现这种情况的原因如下:

    • 本次ajax请求是“非简单请求”,所以请求前会发送一次预检请求(OPTIONS)
    • 服务器端后台接口没有允许OPTIONS请求,导致无法找到对应接口地址

    解决方案: 后端允许options请求。

    如何解决ajax跨域

    一般ajax跨域解决就是通过JSONP解决或者CORS解决,如以下:(注意,现在已经几乎不会再使用JSONP了,所以JSONP了解下即可)

    JSONP方式解决跨域问题

    jsonp解决跨域问题是一个比较古老的方案(实际中不推荐使用),这里做简单介绍(实际项目中如果要使用JSONP,一般会使用JQ等对JSONP进行了封装的类库来进行ajax请求)

    实现原理

    JSONP之所以能够用来解决跨域方案,主要是因为 <script> 脚本拥有跨域能力,而JSONP正是利用这一点来实现。具体原理如图

    实现流程

    JSONP的实现步骤大致如下(参考了来源中的文章)

    • 客户端网页网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制

      function addScriptTag(src) {
        var script = document.createElement('script');
        script.setAttribute("type","text/javascript");
        script.src = src;
        document.body.appendChild(script);
      }
      
      window.onload = function () {
        addScriptTag('http://example.com/ip?callback=foo');
      }
      
      function foo(data) {
        console.log('response data: ' + JSON.stringify(data));
      };                      
          

      请求时,接口地址是作为构建出的脚本标签的src的,这样,当脚本标签构建出来时,最终的src是接口返回的内容

    • 服务端对应的接口在返回参数外面添加函数包裹层
    foo({
      "test": "testData"
    });                     
    • 由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。

    注意,一般的JSONP接口和普通接口返回数据是有区别的,所以接口如果要做JSONO兼容,需要进行判断是否有对应callback关键字参数,如果有则是JSONP请求,返回JSONP数据,否则返回普通数据

    使用注意

    基于JSONP的实现原理,所以JSONP只能是“GET”请求,不能进行较为复杂的POST和其它请求,所以遇到那种情况,就得参考下面的CORS解决跨域了(所以如今它也基本被淘汰了)

    CORS解决跨域问题

    CORS的原理上文中已经介绍了,这里主要介绍的是,实际项目中,后端应该如何配置以解决问题(因为大量项目实践都是由后端进行解决的):

    JAVA后台配置

    JAVA后台配置只需要遵循如下步骤即可:

    • 第一步:获取依赖jar包

      下载 cors-filter-1.7.jarjava-property-utils-1.9.jar 这两个库文件放到lib目录下。(放到对应项目的webcontent/WEB-INF/lib/下)

    • 第二步:如果项目用了Maven构建的,请添加如下依赖到pom.xml中:(非maven请忽视)
    <dependency>
        <groupId>com.thetransactioncompany</groupId>
        <artifactId>cors-filter</artifactId>
        <version>[ version ]</version>
    </dependency>

    其中版本应该是最新的稳定版本,CORS过滤器

    • 第三步:添加CORS配置到项目的Web.xml中( App/WEB-INF/web.xml)
    <!-- 跨域配置-->    
    <filter>
            <!-- The CORS filter with parameters -->
            <filter-name>CORS</filter-name>
            <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
            
            <!-- Note: All parameters are options, if omitted the CORS 
                 Filter will fall back to the respective default values.
              -->
            <init-param>
                <param-name>cors.allowGenericHttpRequests</param-name>
                <param-value>true</param-value>
            </init-param>
            
            <init-param>
                <param-name>cors.allowOrigin</param-name>
                <param-value>*</param-value>
            </init-param>
            
            <init-param>
                <param-name>cors.allowSubdomains</param-name>
                <param-value>false</param-value>
            </init-param>
            
            <init-param>
                <param-name>cors.supportedMethods</param-name>
                <param-value>GET, HEAD, POST, OPTIONS</param-value>
            </init-param>
            
            <init-param>
                <param-name>cors.supportedHeaders</param-name>
                <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>
            </init-param>
            
            <init-param>
                <param-name>cors.exposedHeaders</param-name>
                <!--这里可以添加一些自己的暴露Headers   -->
                <param-value>X-Test-1, X-Test-2</param-value>
            </init-param>
            
            <init-param>
                <param-name>cors.supportsCredentials</param-name>
                <param-value>true</param-value>
            </init-param>
            
            <init-param>
                <param-name>cors.maxAge</param-name>
                <param-value>3600</param-value>
            </init-param>
    
        </filter>
    
        <filter-mapping>
            <!-- CORS Filter mapping -->
            <filter-name>CORS</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    请注意,以上配置文件请放到web.xml的前面,作为第一个filter存在(可以有多个filter的)

    • 第四步:可能的安全模块配置错误(注意,某些框架中-譬如公司私人框架,有安全模块的,有时候这些安全模块配置会影响跨域配置,这时候可以先尝试关闭它们)

    转自:https://segmentfault.com/a/1190000012469713

  • 相关阅读:
    bzoj 1031: [JSOI2007]字符加密Cipher 後綴數組模板題
    hdu3949 XOR xor高斯消元
    The xor-longest Path
    Contest20140906 反思
    Contest20140906 ProblemC 菲波拉契数制 DP
    Contest20140906 ProblemA dp+线段树优化
    bzoj 1257: [CQOI2007]余数之和sum 数学 && 枚举
    tyvj P1716
    BZOJ 1012 [JSOI2008]最大数maxnumber【线段树】
    Bzoj1083 1083: [SCOI2005]繁忙的都市【MST】
  • 原文地址:https://www.cnblogs.com/LeeXiaoYang/p/10276095.html
Copyright © 2011-2022 走看看