ajax跨域问题

简介: ajax跨域问题

为什么会产生跨域问题?


1.浏览器限制


2.请求是跨域的


3.XHR(XMLHttpResquest)请求


jsonp是动态创建script的标签,返回的是js代码,如果服务器没有做任何改动,服务器返回的是json对象,所以浏览器把json对象当做是js代码来解析,就会报错。


jsonp实现原理


jsonp发送的请求是script,所以浏览器不会做校验,如果是XMLHttpResquest就会做校验,这样就可以解决跨域问题。


jsonp是一种非官方协议,它是一种约定,就是前后台约定好一个jsonp参数(可以任意起名字,默认是callback),如果服务器收到参数里面带callback它就知道是jsonp请求,服务器就不会返回json对象,而是返回js代码给前端,函数调用的形式。函数名为callback的参数值。


后台服务器做的变动

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
    public JsonpAdvice() {
        // TODO Auto-generated constructor stub
        super("callback");
    }
}

前台发送普通的ajax请求和jsonp的ajax请求,比较不同点

                               it("get1请求", function(done) {
        // 服务器返回的结果
        var result;
        $.getJSON(base + "/get1").then(function(jsonObj) {
          result = jsonObj;
        });
        // 由于是异步请求,需要使用setTimeout来校验
        setTimeout(function() {
          expect(result).toEqual({
            "data" : "get1 ok"
          });
          // 校验完成,通知jasmine框架
          done();
        }, 100);
      });
      // 测试方法
      it("jsonp请求", function(done) {
        // 服务器返回的结果
        var result;
        $.ajax({
          url: base +"/get1",
          dataType: "jsonp",
          jsonp: "callback",
          cache:true,
          success: function(json){
            result = json;
          }
        });
        // 由于是异步请求,需要使用setTimeout来校验
        setTimeout(function() {
          expect(result).toEqual({
            "data" : "get1 ok"
          });
          // 校验完成,通知jasmine框架
          done();
        }, 100);
      });

20180505135110127.png

两种的请求方式不一样,jsonp发送的请求是script类型,返回的是js对象所以不会拦截。callback后面带的就是参数,返回的js的函数名就是这个参数。

20180505135946294.png

jsonp的弊端


服务器代码需要改动。(如果服务器的代码是第三方的就没法使用了)

只支持get方法(不安全,满足不了需求)


发送的不是XMLHttpResquest请求(就不能使用它的特性)


跨域问题的另外两种解决方式


1.浏览器发出请求被调用方,要在被调用方进行修改,这个修改是基于http协议关于跨域问题方面的规定,就是在返回头里面添加一些字段,告诉浏览器我这边允许对方调用。那么浏览器就不会报跨域问题了。

被调用方做修改告诉浏览器我这边允许对方调用。


跨域请求的请求头里面会多一个origin的字段。存放当前域名信息,浏览器发现是跨域请求的时候就会在请求头多加这个字段,等请求返回来,就会检查相应头里面有没有允许的跨域信息,如果没有就会报错。


简单的跨域请求


1). 请求方法是GET、HEAD或者POST,并且当请求方法是POST时,请求header里面没有自定义头,Content-Type必须是application/x-www-form-urlencoded, multipart/form-data或着text/plain中的一个值。


复杂的跨域请求


例如发送json格式的请求,put,delete方法的请求

复杂的跨域请求(如带自定义header的跨域请求),在发送真实请求前都会先发送OPTIONS请求,浏览器根据OPTIONS请求返回的结果来决定是否继续发送真实的请求进行跨域资源访问。所以复杂请求肯定会两次请求服务端。


连续两次请求会影响性能,应对这种跨域预检机制,后台可以通过设置Access-Control-Max-Age来控制浏览器在多长时间内(单位s)无需在请求时发送预检请求。


所以在服务器加上允许的头。

import java.io.IOException;
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 org.apache.tomcat.util.buf.StringUtils;
public class CrosFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletResponse res = (HttpServletResponse) response;
        HttpServletRequest req = (HttpServletRequest) request;
        //获取请求调用方的域名
        String origin = req.getHeader("Origin");
        if (!org.springframework.util.StringUtils.isEmpty(origin)) {
            //带cookie的时候,origin必须是全匹配,不能使用*
            //允许跨域调用的域名
            res.addHeader("Access-Control-Allow-Origin", origin);            
        }
        //指定允许的方法
        res.addHeader("Access-Control-Allow-Methods", "*");
        String headers = req.getHeader("Access-Control-Request-Headers");
        // 支持所有自定义头
        if (!org.springframework.util.StringUtils.isEmpty(headers)) {
            res.addHeader("Access-Control-Allow-Headers", headers);            
        }
        //在一个小时之内可以缓存信息,不需要再发送预检命令
        res.addHeader("Access-Control-Max-Age", "3600");
        //能够支持带cookie的跨域请求
        res.addHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
}

如果使用SpringMvc框架的话在请求上注解 @CrossOrigin(origins = "*", maxAge = 3600)  ,这里要强调的是springMVC的版本要在4.2或以上版本才支持@CrossOrigin,我这里的设置是允许所有跨域访问,也可以单独指定允许的服务器跨域(设置origin的值便可)。


2.隐藏跨域的思路。请求不是浏览器发出,是从中间的http服务器转出去的,通过http转发之后,浏览器会发现所有的请求都是用一个域,就不会报跨域问题。调用方做修改。


可以利用nginx作为中间服务器,进行转发请求。

相关文章
|
8月前
|
前端开发 JavaScript Java
SpringBoot Ajax跨域问题(session共享问题)
ajax 发送post请求至springBoot出现跨域问题 需要在springBoot加上注解 @CrossOrigin 就能解决
40 0
|
9月前
|
JavaScript 前端开发 安全
vue中解决ajax跨域问题(no “access-control-allow-origin”)
产生原因 跨域是是因为浏览器的同源策略限制,是浏览器的一种安全机制,服务端之间是不存在跨域的。 所谓同源指的是两个页面具有相同的协议、主机和端口,三者有任一不相同即会产生跨域。
127 0
|
11月前
|
JSON JavaScript 前端开发
jsonp解决Ajax跨域问题
jsonp解决Ajax跨域问题
80 0
|
11月前
|
前端开发 JavaScript
Vue —— 进阶 AJAX(解决开发环境 Ajax 跨域问题)
Vue —— 进阶 AJAX(解决开发环境 Ajax 跨域问题)
105 0
|
前端开发 JavaScript 安全
Ajax&Fetch学习笔记 03、跨域问题
Ajax&Fetch学习笔记 03、跨域问题
Ajax&Fetch学习笔记 03、跨域问题
|
JSON 前端开发 JavaScript
|
JSON JavaScript 前端开发
学习AJAX必知必会(5)~同源策略、解决跨域问题(JSONP、CORS)
学习AJAX必知必会(5)~同源策略、解决跨域问题(JSONP、CORS)
224 0
学习AJAX必知必会(5)~同源策略、解决跨域问题(JSONP、CORS)
|
JavaScript 前端开发 PHP
通过js(ajax)请求另外一个域名的接口时会产生跨域问题解决办法
通过js(ajax)请求另外一个域名的接口时会产生跨域问题解决办法
261 0
|
前端开发 Java Windows
Java 通过 HttpConnection 解决 Ajax 请求跨域问题
版权声明:本文首发 http://asing1elife.com ,转载请注明出处。 https://blog.csdn.net/asing1elife/article/details/82788062 ...
1268 0