跨域

crosDomain.png

服务器端解决,通过一个filter过滤来自移动端服务器的请求,为response添加Access-Control-Allow信息。通过设置Access-Control-Allow-Credentials=true允许客户端发送cookie,客户端需要设置XMLHttpRequest()的withCredentials 属性为true

 var xhr = new XMLHttpRequest();
    xhr.withCredentials = true;

在ionic中需要设置$http:

  $http({
          method: "GET",
          url: url,
          params: params,
          cache: false,
          timeout: 20000,
          withCredentials:true,
          headers: {'Content-Type': 'application/json;charset=UTF-8','Cache-Control':'no-cache'}
        }).then(function (result) {          
            ...
          }

跨域小知识

客户端ClientA请求服务器server1,server1的页面中使用ajax请求了server2中的数据就发生了跨域。默认情况,浏览器不允许跨域请求。大致解决思路有:

浏览器端解决。

适合开发者自己调试, 在chrome浏览器中添加启动参数:

--args --disable-web-security --user-data-dir 

server端解决方案JSONP。

通过某些手段规避浏览器的跨域规则,比如使用JSONP等,JSONP需要客户端与服务器端配合。
网页通过动态插入<script>元素,由它向跨源网址发出请求,不再受跨域规则限制。
推荐JQuery,在ajax请求中指定dataType:'jsonp'的方式。这种方式自动实现<script>加回调函数的效果。
js代码

<script type="text/javascript" src="jquery.js"></script>  
<script type="text/javascript">  
    $.ajax({  
        url:"http://crossdomain.com/services.php",  
        dataType:'jsonp',  
        data:'',  
        jsonp:'callback',  
        success:function(result) {  
            for(var i in result) {  
                alert(i+":"+result[i]);//循环输出a:1,b:2,etc.  
            }  
        },  
        timeout:3000  
    });  
</script>

这种方法需要js实现处理返回结果的回调函数,如果有很多页面跨域,实现这些回调函数挺烦人的。
服务器端实现,在原来的返回结果基础上添加回调函数名称和括号,默认用success,也可以配合jQuery的ajax请求指定函数名称。
支持跨域前的返回:

['data1','data2']

为支持jsonp,修改后的返回:

callbackFunction(['data1','data2'])

server端实现方案2,通过Allow-Control-Access机制。

现代浏览器都通过Allow-Control-Access机制允许跨域,原理如下:

  1. 浏览器发现存在跨域请求,不直接拒绝,而是向服务器server2发多送一个Origin字段把server1的IP地址加端口告知server2,如果是put、delete这种高危请求,浏览器先发送一个options类型的请求。
  2. 如果server2没有任何允许跨域的意思,浏览器不再处理服务器的响应,而是报一个跨域错误。
  3. 如果server2允许跨域,需要在response中通知浏览器,告知浏览器允许谁跨域,允许不允许浏览器发送cookie信息。
  4. 浏览器检查server2返回的信息,如果当前请求合乎规则,则进一步处理服务器端响应,执行js,展示页面。
    server2允许跨域的java端实现,通过filter为response添加Allow-Control-Access信息:
package org.example.core.filter;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jodd.util.StringUtil;

/**
 * @author damowang 20170802 解决移动端开发浏览器跨域问题
 *
 */
public class CORSFilter implements Filter {
    /**客户端域名,通过init-param配置,在filter初始化时赋值*/
    private String allowOrigin;

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest srequest, ServletResponse sresponse,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) sresponse;
        HttpServletRequest request = (HttpServletRequest) srequest;     
        //设置允许谁(server1的域名或ip)跨域,在一次request中Access-Control-Allow-Methods只能设置一个客户端地址,因此通过判断客户端设置该字段
        if (StringUtil.isNotEmpty(allowOrigin)) {
            List<String> allowOriginList = Arrays.asList(allowOrigin.split(","));
            String currentOrigin = request.getHeader("Origin");
            if (allowOriginList.contains(currentOrigin)) {
                response.setHeader("Access-Control-Allow-Origin", currentOrigin);
            }
        }
        response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
        response.setHeader("Access-Control-Allow-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Cache-Control,Content-Type");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(request, response);

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        allowOrigin = filterConfig.getInitParameter("allowOrigin");

    }
}

web.xml中配置拦截器

<!-- 跨域拦截器 -->
  <filter>
      <filter-name>corsFilter</filter-name>
      <filter-class>org.example.core.filter.CORSFilter</filter-class>
      
      <init-param>
          <param-name>allowOrigin</param-name>
          <param-value>http://server1.com:8100,http://anotherDomainOfServer1.com</param-value>
      </init-param>
  </filter>
  <filter-mapping>
      <filter-name>corsFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

客户端允许发送cookie:

 var xhr = new XMLHttpRequest();
 xhr.withCredentials = true;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容