全网最全最详细的跨域解决方案

你们好,我是金金金。

在这里插入图片描述

前置知识

本篇文章以通俗易懂的方式进行描述,自己组织语言进行输出,尽量让每一个人都能看得懂。哪里有说的不正确的地方 大佬请在评论区指正!

  • 首先需要了解浏览器的同源策略

浏览器的同源策略

在这里插入图片描述

简单来说,同源策略是浏览器的一项重要安全机制,它限制了从一个来源加载的脚本如何与来自另一个来源的资源进行交互。其目的是防止不同来源之间的恶意行为,例如跨站脚本攻击(XSS)和跨站请求伪造(CSRF)

怎么算同源?

两个 URL协议域名端口 必须完全相同,才被认为是同源。否则,它们被认为是不同源的,那么就会发生跨域。如下

在这里插入图片描述

什么是跨域?

了解了浏览器的同源策略之后,想必你心中已经有答案了吧,两个 URL协议域名端口 有一个不同那么就会发生跨域,控制台报错如下

在这里插入图片描述

如何解决跨域?

  • 这里我分为前端后端分别讲解具体的解决方案。

前端

vite代理

  • 例如vitewebpack都有配置代理能解决跨域的一个方案。这里只讲解vite
  1. vite.config.ts配置文件:通过 server.proxy 选项来配置代理规则,我这里是ts项目,项目下一般都会有一个vite.config.ts,不是ts的项目那么就是.js文件,都差不多,配置如下:图中写明了各个参数意思

在这里插入图片描述

在这里插入图片描述

  1. 然后在你封装请求的文件当中使用这个/api 作为接口基准url即可

在这里插入图片描述

需要注意:Vite 的代理功能仅限于开发阶段,不会对生产环境产生任何影响。在生产环境中,你需要通过其他方式来处理跨域问题,比如在后端服务器上启用 CORS,或者在反向代理服务器(如 Nginx)上进行配置。

JSONP

原理

利用 <script> 标签的 src 属性没有跨域限制的特性来实现跨域数据访问

怎么做呢

事先定义一个用于获取跨域响应数据的回调函数,并通过没有同源策略限制的script标签发起一个请求(将回调函数的名称放到这个请求的query参数里),然后服务端返回这个回调函数的执行,并将需要响应的数据放到回调函数的参数里,前端的script标签请求到这个执行的回调函数后会立马执行,于是就拿到了执行的响应数据。

  • 参考代码如下:
function handleResponse(response) {
  //处理服务器返回的数据
}

var script = document.createElement('script');
script.src = 'https://jsonp.com/data?callback=handleResponse';
document.body.appendChild(script);

注意JSONP只支持GET请求,因为它依赖于<script>标签的跨域特性,而<script>标签不支持POST等其他HTTP方法

无需过多研究,了解即可,因为现在基本不会用到这种方式,感兴趣的小伙伴们自行百度~

选哪种?

如果你们项目开发阶段联调跨域,后端让前端解决的话 优先选择第一种:代理方式即可!

服务端

  • 这里以Java为例子

返回新的CorsFilter

@Configuration
public class GlobalCorsConfig {

  /**
   * 配置跨域过滤器
   * 允许特定条件下的跨域请求,以适应前端开发需求
   *
   * @return CorsFilter 配置好的跨域过滤器实例
   */
  @Bean
  public CorsFilter corsFilter() {
    // 创建一个新的CORS配置实例
    CorsConfiguration config = new CorsConfiguration();

    // 允许所有域名进行跨域调用
    config.addAllowedOrigin("*");
    // 允许跨越发送Cookie
    config.setAllowCredentials(true);
    // 允许所有头部信息进行跨域调用
    config.addAllowedHeader("*");
    // 允许所有请求方法进行跨域调用
    config.addAllowedMethod("*");

    // 创建一个URL基于CORS配置的源
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // 将CORS配置应用到所有路径
    source.registerCorsConfiguration("/**", config);

    // 返回基于所配置的源创建的CORS过滤器实例
    return new CorsFilter(source);
  }
}

全局跨域

注意:需要确保Spring能扫描到这个配置类。

重写WebMvcConfigurer

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  //配置了所有的路由都可以跨域请求
                .allowedHeaders("*")  //配置了允许发送的自定义请求头
                .allowedMethods("*")  //配置了路径下所有的请求都可以跨域请求
                .allowedOriginPatterns("*")  //解决跨域资源共享(CORS)问题的一个配置项,用于允许来自任何来源的跨域请求
                .allowCredentials(true)  //指定在跨域请求中是否允许浏览器发送包含凭证信息的请求
                .maxAge(3600);  //指定在给定的时间范围内,是否允许浏览器缓存特定资源的请求结果。
    }
 
}

全局跨域

注意:需要确保Spring能扫描到这个配置类。

使用CrossOrigin注解

针对某个控制器方法配置跨域
@RestController public class MyController { 
    @CrossOrigin(origins = "http://example.com") // 允许来自指定域的跨域请求,"*"代表全部
    @GetMapping("/api/data") 
    public String getData() { 
        return "This is cross-origin data"; 
    } 
}
针对整个控制器配置跨域

@RestController
@CrossOrigin(origins = "*")
public class TestController {
    @RequestMapping("/test")
    public String test() {
        return "This is cross-origin data";
    }
}

局部跨域

无论是针对某个控制器方法还是针对整个控制器配置,都是属于局部配置,不建议使用,繁琐。

手动设置响应头


@RestController
public class TestController {
    @RequestMapping("/test")
    public HashMap<String, Object> test(HttpServletResponse response) {
        // 设置跨域
        response.setHeader("Access-Control-Allow-Origin", "*");
        return new HashMap<String, Object>() {{
            put("state", 200);
            put("data", "success");
            put("msg", "");
        }};
    }

局部跨域

纯手动添加响应头,不建议使用。繁琐。每个方法都得写

实现ResponseBodyAdvice

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
  /**
   * 内容是否需要重写(通过此方法可以选择性部分控制器和方法进行重写)
   *
   * @param methodParameter 方法参数,包含了方法的信息以及参数的信息
   * @param aClass          返回值的类型
   * @return 返回ture表示重写
   */
  @Override
  public boolean supports(MethodParameter methodParameter, Class aClass) {
    return true;
  }

  /**
   * 方法返回之前调用此方法
   *
   * @param o                  方法返回值
   * @param methodParameter    方法参数,包含了方法的信息以及参数的信息
   * @param mediaType          返回值的类型
   * @param aClass             返回值的类型
   * @param serverHttpRequest  请求
   * @param serverHttpResponse 响应
   * @return
   */
  @Override
  public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
    // 设置跨域
    serverHttpResponse.getHeaders().set("Access-Control-Allow-Origin", "*");
    return o;
  }
}

全局跨域

注意:需要确保Spring能扫描到这个配置类。

Nginx解决跨域

  • Nginx 服务器的配置文件中添加以下代码

在这里插入图片描述

server {
    listen       80;
    server_name  your_domain.com;
    location /api {
        # 允许跨域请求的域名,* 表示允许所有域名访问
        add_header 'Access-Control-Allow-Origin' '*';

        # 允许跨域请求的方法
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

        # 允许跨域请求的自定义 Header
        add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept';

        # 允许跨域请求的 Credential
        add_header 'Access-Control-Allow-Credentials' 'true';

        # 预检请求的存活时间,即 Options 请求的响应缓存时间
        add_header 'Access-Control-Max-Age' 3600;

        # 处理预检请求
        if ($request_method = 'OPTIONS') {
            return 204;
        }
    }
    # 其他配置...
}

server { listen 80; server_name your_domain.com; }

作用: 定义服务器监听的端口和域名。

解释: listen 80 表示服务器监听 80 端口,这是 HTTP 的默认端口。server_name your_domain.com 表示该服务器处理 your_domain.com 的请求。这里的 server 块是 Nginx 配置的基础结构,用于定义服务器如何处理特定域名的请求。

结语

耐心看完本篇文章,解决跨域就是简简单单轻轻松松

好啦,本篇文章到此结束,选择适合你们的一种解决方案吧~

  • 编写有误还请大佬指正,万分感谢。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值