zoukankan      html  css  js  c++  java
  • AJAX跨域

    AJAX跨域完全讲解

    今天在慕课网上学习了AJAX跨域完全讲解:https://www.imooc.com/learn/947

    我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候知道了为什么会存在跨域,以及跨域解决的方案有哪些,今天随着课程的学习,又加深了AJAX跨域的理解,以此记录下来。

    关于ajax更详细的文章见:https://segmentfault.com/a/1190000012469713

    为什么会发生产生跨域问题?

    上面的图也很清晰了,因为浏览器为了安全(同源),本身就限制了。

    • 当我们发送XMLHttpRequest请求的时候,如果请求的是别的域(主机域名、端口)不同时,那么就会产生跨域问题(客户端无法获取服务端返回的数据)

    值得注意的是:跨域的问题是发生在XMLHttpRequest请求的,也就是说,不是XMLHttpRequest请求是不会有跨域问题的

    • 举个很简单的例子:在编写网页的时候,<img = src = www.xxxx.xxxx/ >,URL不是本域的还是可以正常获取该图片的

    解决跨域问题的思路

    明显地,跨域的问题是由于浏览器限制的,是XMLHttpRequest才会发生的,那么我们可以以这个思路去找找解决思路:

    对于浏览器的问题,可以使用相关的参数进行启动浏览器,是可以解决跨域的问题,但是通用性是极低的,了解即可。

    JSONP解决跨域

    JSONP是JSON使用的一种补充方式,不是官方的协议。JSONP是一种解决跨域问题的一种协议

    JSONP这种解决方案其实现在已经很少用了(复杂一点,需要修改后台代码),但我们可以适当了解一下。

    使用步骤

    在后端增加一个控制器,继承AbstractJsonpResponseBodyAdvice类,完整代码如下:

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

    前端ajax请求:

    // 服务器返回的结果
        var result;
    
        $.ajax({
            url: base +"/get1",
            dataType: "jsonp",
            jsonp: "callback2",
    
            //是否需要缓存,如果这里没有配置缓存,那么请求的URL还会有一个参数
            cache:true,
            success: function(json){
                result = json;
            }
        });
     

    注意的是,前端AJAX的jsonp: "callback2",要和我们的Controllersuper("callback2");是一致的,不然是不会有效的。

    JSONP原理是动态创建script来进行请求的:

    JSONP的弊端:

    • 要对服务器的代码进行改动
    • 只支持GET方法(原理是动态创建script来进行请求的)
    • 发送的不是XMLHttpRequest请求(XMLHttpRequest请求有很多好用的特性)

    参考资料:

    CORS解决跨域问题

    CORS解决跨域问题(也就是我们服务端被调用方解决跨域的思路)

    对于CORS是怎么理解的,我就直接摘抄一下:https://segmentfault.com/a/1190000012469713#articleHeader8的了。

    在Java中,我们写下面这个过滤器,就可以完全解决跨域的问题了:

    package com.imooc;
    
    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;
            
            
            //带cookie的时候,origin必须是全匹配,不能使用*
            String origin = req.getHeader("Origin");
            if (!org.springframework.util.StringUtils.isEmpty(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");
            // enable cookie
            res.addHeader("Access-Control-Allow-Credentials", "true");
            chain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
    
        }
    
    }
     

    上面提到了非简单请求,那什么是非简单请求呢,可以看下面的图:

    非简单请求会发出一个预检命令的(当然了,我们上面的Filter已经解决预检命令的问题了):

    Spring框架解决

    如果使用的是Spring框架的话,那就只需要一个注解就能够解决跨域的问题了@CrossOrigin

    HTTP服务器层

    我们在的商用开发中,一般请求的过程是这样的:浏览器->HTTP服务器(Nginx,Apache)->应用服务器(Tomcat,Weblogic)

    上面编写的Filter、Spring框架都是在应用服务器上解决的,我们也是可以通过HTTP服务器(Nginx,Apache)来进行解决跨域问题的

    Nginx我用过,Apache我倒是还没用过,下面就简单记录了Nginx和Apache是如何配置的:

    Nginx配置:

    Apache配置:

    代理解决跨域问题

    在之前的图我们已经看到了,解决跨域的问题可以在“调用方”中来进行解决。

    “调用方”解决跨域的问题是这个思路的:让发送出去的请求代理成是本域的

    举个例子:

    www.zhongfucheng.top是调用方
    
    www.zhongfucheng.site是被调用方
    

    它俩是不同域的,但我们可以在nginx或Apache上进行配置代理:将被调用方www.zhongfucheng.site映射成别的路径

    比如,像下面的图,将8080端口的映射成了ajaxServer,当调用方访问ajaxServer路径时,这样的方法在外部看起来就不像是跨域了,像是访问本地(8081端口),但实际访问别的域(8080端口)

    总结

    令我感到最简单的是通过Spring的注解就可以解决跨域的问题了,JSONP的方式已经是很少用的了,因为存在一定的弊端,但了解一下也无妨,毕竟可能面试的时候会问到。当没有用任何框架的时候,写Filter也不麻烦,也只是配置了一下HTTP头信息而已。如果使用Nginx、Apache时,也可以用代理或者配置HTTP头信息都可以解决。看完之后,有没有觉得跨域问题就迎刃而解了。

  • 相关阅读:
    2、容器初探
    3、二叉树:先序,中序,后序循环遍历详解
    Hebbian Learning Rule
    论文笔记 Weakly-Supervised Spatial Context Networks
    在Caffe添加Python layer详细步骤
    论文笔记 Learning to Compare Image Patches via Convolutional Neural Networks
    Deconvolution 反卷积理解
    论文笔记 Feature Pyramid Networks for Object Detection
    Caffe2 初识
    论文笔记 Densely Connected Convolutional Networks
  • 原文地址:https://www.cnblogs.com/syp172654682/p/8671664.html
Copyright © 2011-2022 走看看