Ajax跨域问题及其解决方案

什么是 ajax 跨域

主流的前后端分离模式下,当前端调用后台接口时,由于是在非同一个域下的请求,从而会引发浏览器的自我安全保护机制,最终结果是接口成功请求并响应,但前端不能正常处理该返回数据

Access-Control-Allow-Origin

因此,当同时满足以下三个条件的情况下,就会出现跨域问题:

  1. 浏览器限制
  2. 非同源请求(跨域)
  3. 发送的是 XHR ( XMLHttpRequest ) 请求

跨域问题

解决方案

想要彻底解决跨域问题,只需要破坏以上三个条件的任一即可:

1. 修改浏览器(不推荐

添加浏览器启动参数:chrome --disable-web-security,但是极不推荐这种解决方式。

2. JSONP请求(不常用

Jsonp,全称 JSON with Padding,一种非官方的协议,而是一种约定;前端通过向后台发送 script 类型请求解决跨域,此时接口响应的 application/javascript 类型的数据会作为 callback 函数的参数进行处理。

Jsonp Request

所以,后台也需要做相应的处理。以 Java 为例,添加如下配置即可:

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

    public JsonpAdvice() {
        // 前后端约定的jsonp参数名,默认值是callback
        super("callback");
    }
    
}

注意,Spring 4.1 版本之后,官方已不再推荐使用上述允许 jsonp 请求的配置,建议使用 CROS 配置来解决跨域问题,详情可查看这里

综上,jsonp 请求存在以下几个弊端:

  1. 服务端需要改动代码进行支持;
  2. 只支持发送 Get 请求,请求头中更改其它类型的请求方式是无效的;
  3. 发送的不是 XHR 请求,而是 script 类型,无法享受到相关的特性。

3. 调用方隐藏跨域

NginxApache 来代理调用方的请求(客户端变更为相对路径请求,而非绝对路径),此时对于浏览器来说,由于请求是同源的,因此就不存在跨域问题。

4. 被调用方允许跨域(最常用

  • 服务端配置

以 Java 应用为例,添加如下全局配置:

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 允许跨域的接口
                .allowedOrigins("*")  // 允许跨域的请求源
                .allowedMethods("*")  // 允许跨域的请求方式
                .allowedHeaders("*") // 允许跨域的请求头
                .allowCredentials(true)  // 带cookie请求的时候需要开启,且allowedOrigins需要指定为具体的请求源(最好是动态配置)
                .maxAge(60 * 60 * 24); // 设定options请求预检命令的缓存时长
    }

}

如果只想针对某个类下的接口,或者是某个具体的接口配置允许跨域,只需要在相应的地方添加注解 @CrossOrigin 即可。

  • Nginx 配置

如果配置了 nginx 作为代理服务器,那么只需要为 nginx 添加支持跨域请求即可:

    server {
        listen 80;
        server_name xxx.com;

        location / {
            proxy_pass http://localhost:8080/;

            # 配置允许跨域
            add_header Access-Control-Allow-Origin $http_origin;
            add_header Access-Control-Allow-Methods *;
            add_header Access-Control-Allow-Headers $http_access_control_request_headers;
            add_header Access-Control-Max-Age 3600;
            add_header Access-Control-Allow-Credentials true;
            
            # 对于options预检请求,直接响应200
            if ($request_method = OPTIONS) {
                return 200;
            }
        }
    }

扩展思考

Q1:浏览器在执行跨域请求时,是先执行后判断,还是先判断后执行? A1:都有可能,这需要根据所发送的请求是简单请求还是非简单请求来判断;如果是非简单请求,浏览器每次在执行真正的请求之前,还会先发送一个 options 请求方式的预检命令【 可设定缓存时长,取消每次请求都要预检,提高效率,参考上面的服务端配置 】。关于两种请求的区分及定义,参考下图说明:

简单请求 VS 非简单请求

Q2:如果是允许带(被调用方cookie 的跨域请求,此时服务端同样配置为 Access-Control-Allow-Origin 等于 *,前端是否还可以请求成功? A2:不可以,此时要将 Access-Control-Allow-Origin 指定为调用方具体的域【 可以先取得调用方的域再动态配置,这样就不存在多个域请求的限制问题 】,并且添加配置 Access-Control-Allow-Credentialstrue

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏TungHsu

这或许是对小白最友好的python入门了吧——1,python环境的搭建。

这里我们的教程以Windows系统为例, 首先在桌面上按住shift键并右击,选择“在此处打开powershell窗口”如下图: ? 然后就会出来一个酱紫的东西...

2847
来自专栏Java学习123

Centos6.5设置Tomcat7管理员用户名和密码

3236
来自专栏技术小讲堂

在ASP.NET 5应用程序中的跨域请求功能详解什么是“同域”添加CORS包在应用程序中配置CORSCORS策略选项跨域请求中的凭据设置先行请求的过期时间CORS是怎么样工作的先行请求

浏览器安全阻止了一个网页中向另外一个域提交请求,这个限制叫做同域策咯(same-origin policy),这组织了一个恶意网站从另外一个网站读取敏感数据,但...

3375
来自专栏Laoqi's Linux运维专列

Nginx 启动、停止、平滑重启和平滑升级

8494
来自专栏快乐八哥

ui-router中使用ocLazyLoad和resolve

1.AngularJS按需加载 AngularJS主要应用开发SPA(Single Page Application)项目,所以在小型项目中,services、...

2517
来自专栏gaoqin31

Ajax跨域

我们可以在www.a.com的js前端请求 www.a.com然后www.a.com请求www.b.com的数据

1542
来自专栏技术记录

centOS7 mini配置linux服务器(二) 配置IP

1.登录root用户,输入指令  #ip addr 可以看到除lo外的属于你的网卡配置。 ? 2.输入 #cd /etc/sysconfig/network-...

2168
来自专栏HTML5学堂

服务器代由跨域以及各类跨域方法比较与总结

在之前的文章当中,我们依次介绍了iframe跨域、JSONP跨域以及postMessage跨域。今天我们将针对跨域进行收尾,讲解最后一种,也是比较常见的服务器代...

37314
来自专栏北京马哥教育

2行Python代码生成图片验证码

graphic-verification-code 生成图片验证码 安装 使用 编测 Python2.7下测试可用,Python3.5导...

3678
来自专栏前端之心

跨域问题详解

做过 web 开发的同学,应该都遇到过跨域的问题,当我们从一个域名向另一个域名发送 Ajax 请求的时候,打开浏览器控制台就会看到跨域错误,今天我们就来聊聊跨域...

3383

扫码关注云+社区

领取腾讯云代金券