当前位置 博文首页 > 编程小马:一文带你彻底搞懂JS前端跨域请求

    编程小马:一文带你彻底搞懂JS前端跨域请求

    作者:[db:作者] 时间:2021-09-17 15:24

    什么是跨域请求

    1. 在前端开发编码过程中,常见的 html 标签例如:a、form、img、script、link、iframe以及 Ajax 操作都可以指向一个资源地址或者说可以发起对一个资源的请求,那么这里所说的请求就存在同域请求还是跨域请求。
    2. 所谓跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一致(这里所有的域是协议、域名和端口号的合集,同域就是所协议、域名和端口号均相同,任何一个不同都是跨域)。

    常见的跨域场景如下:

    源 URL请求 URL是否跨域说明
    http://mcy.com/ahttp://mcy.com/b同协议同域名同端口号,不同请求,不算跨域请求
    http://mcy.com/ahttp://mcy.com:8080/b端口不同
    http://mcy.com/ahttps://mcy.com/b协议不同
    http://www.mcy.com/ahttp://mcy.a.com/b主域名相同,但是子域名不相同
    http://mcy.com/ahttp://abc.com/b域名不相同

    为什么要使用跨域请求

    1. 在现代前端开发中,我们经常需要调用第三方的服务接口(例如 mock server、fake api),随着专业化分工的出现有很多专业的信息服务提供商为前端开发者提供各类接口,这种情况下就需要进行跨域请求(这类前端接口服务很多是采用的 cors 方式来解决跨域问题的)。
    2. 还有一类情况是在前后端分离的项目中,前端后端分属于不同的服务跨域问题在采用这种架构的时候就存在。而且现在很多项目都采用这种前后分离的方式。

    跨域请求实现

    一、jsonp 跨域

    通常为了减轻web服务器的负载,我们可以引入其他服务器上的js、css,img等静态资源,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域请求。
    1、原生实现

    var script = document.createElement('script');
    script.type = 'text/javascript';
    
    // 传参并指定回调执行函数为onBack
    script.src = 'http://machaoyin.top:8080/user/findById?id=1&callback=back';
    document.head.appendChild(script);
    
    // 回调执行函数
    function back(data) {
    	console.log(data);
    }
    
    

    原生实现除了这样写,还可以自己使用script标签请求,具体代码如下;

    // 回调执行函数
    function back(data) {
    	console.log(data);
    } 
    //跨域请求
    <script src="http://machaoyin.top:8080/user/findById?id=1&callback=back"></script>
    

    后端返回方法(根据id查询数据)

    @GetMapping(value = "findById")
    @ApiOperation(value = "根据id获取用户信息", notes = "根据id查询用户信息")
    public String getUser(Integer id, HttpServletRequest request, HttpServletResponse response){
        String callback = (String)request.getParameter("callback");
        User user = userService.findById(id);
        JSONObject jsonObject = JSONObject.fromObject(user);
        String retStr = callback + "(" + jsonObject + ")";
        return retStr;
    }
    

    返回查询的对象数据。其中使用JSONObject把JavaBean对象转为json字符串。JSONObject的使用请移步:浅谈JSONObject的使用
    测试代码中请求的地址为我服务器地址,后端请求接口方法使用的Swagger来维护接口规范,详情请访问:SpringBoot整合Swagger2
    请求的结果如图:
    在这里插入图片描述
    2、Jquery AJAX实现

    $.ajax({
    	url: 'http://machaoyin.top:8080/user/findById?id=1',
    	type: 'get',
    	dataType: 'jsonp',  // 请求方式为jsonp
    	success:function(data){     
    		console.log(data);   
    	}
    }); 
    
    

    【注】返回结果和原生实现返回的一样。使用jsonp很方便也很简单,但有一个缺点就是只能发送get请求,AJAX设置post方法也是发送get请求。

    二、跨域资源共享 CORS

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源(协议 + 域名 + 端口)服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同域使用的限制。
    CORS需要浏览器和服务器同时支持。它的通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX/Fetch通信没有差别,代码完全一样。浏览器一旦发现请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器端实现了CORS接口,就可以跨域请求。

    后端CORS接口案例:

    @CrossOrigin(origins = "*")
    @PostMapping(value = "/find")
    @ApiOperation(value = "根据id获取用户信息", notes = "根据id查询用户信息")
    public User find(Integer id){
        return userService.findById(id);
    }
    

    在SpringMVC中可以直接使用注解@CrossOrigin来解决跨域接口的问题。
    @CrossOrigin有两个参数

    1. maxAge:最长响应时间(单位是秒)。
    2. origins:允许对哪些地址进行响应(*不限制)。

    web项目中可以通过HttpServletResponse 来设置,具体代码如下:

    @RequestMapping(value = "/find")
    @ApiOperation(value = "根据id获取用户信息", notes = "根据id查询用户信息")
    public User find(Integer id, HttpServletResponse  res){
        //允许请求的地址
        res.setHeader("Access-Control-Allow-Origin", "*");
        //请求方式,也可以在请求注解上设置
        res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        //最长响应时间
        res.setHeader("Access-Control-Max-Age", 60);
        return userService.findById(id);
    }
    

    前台跨域请求不需要任何改变,和平常的AJAX请求一样即可,如下:

    $.ajax({
    	url: 'http://machaoyin.top:8080/user/find?id=1',
    	type: 'post',
    	success: function(data){
    		console.log(data);
    	}
    });
    

    请求结果和上面的一样,这里就不多展示了。

    【注】 jsonp跨域请求和跨域资源共享 CORS最大区别在也jsonp只能发送get请求,而CORS可以发送http的任一请求类型。


    最后有什么不足之处,欢迎大家指出,期待与你的交流。如果感觉对你有帮助,点个赞在走呗 O(∩_∩)O ~

    cs