开发者社区> java3y> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

AJAX跨域完全讲解

简介: AJAX跨域完全讲解 今天在慕课网上学习了AJAX跨域完全讲解:https://www.imooc.com/learn/947 我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候知道了为什么会存在跨域,以及跨域解决的方案有哪些,今天随着课程的学习,又加深了AJAX跨域的理解,以此记录下来。
+关注继续查看

AJAX跨域完全讲解

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

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

img_f8e0ba2b85a3298c33a5ae3c05ae96d3.png

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

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

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

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

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

解决跨域问题的思路

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

img_badb48d9fd30dd2eada092fae716dad3.png

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

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来进行请求的:

img_90ecb0e0a87de2b57e0bfd396349cb54.png

JSONP的弊端:

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

参考资料:

CORS解决跨域问题

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

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

img_d4e0e9048f625f525fe123fa53705b8e.png

在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

    }

}

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

img_5eb74b950f3250217aa2b422100852ed.png

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

img_90ecb0e0a87de2b57e0bfd396349cb54.png

Spring框架解决

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

HTTP服务器层

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

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

img_0068a403c4fbdb22d2c9571dea4d095e.png

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

Nginx配置:
img_d459818812789be52841c04d8fa6b2e0.png

Apache配置:

img_1b8a7a6806a44c380d9ef5d5b2c21393.png

代理解决跨域问题

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

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

举个例子:

www.zhongfucheng.top是调用方

www.zhongfucheng.site是被调用方

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

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

img_2b92681631314a8f1e9054466a4a03c6.png

总结

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


如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y

更多的文章可往:文章的目录导航

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Ajax跨域解决方案
讲述跨域原因以及从原理上讲述两种解决方案:jsonp,options
4588 0
ajax 跨域----好用的解决方案
一、前言 跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了! 但是感觉还是差了点什么,于是现在重新梳理了一下。个人见识有限,如有差错,请多多见谅 二、前言 关于跨域,有N种类型,本文只专注于 ajax请求跨域(ajax跨域只是属于浏览器"同源...
1960 0
ajax跨域和js跨域解决方案 .
  ajax跨域和JS的跨域通信(Cross The Site)的几种解决方案     最近做的一个项目中需要ajax跨域取得数据,如果是在本域中确实没有问题,但是放到二级域和其他域下浏览器直接就弹出提示框:“该页正在 1.什么引起了ajax跨域不能的问题 ajax本身实际上是通过XMLHttpRequest对象来进行数据的交互,而浏览器出于安全考虑,不允许js代码进行跨域操作,所以会警告。
1040 0
+关注
java3y
公众号:Java3y。文章导航:https://github.com/ZhongFuCheng3y
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载