美文网首页
你又遇到跨域问题了吗

你又遇到跨域问题了吗

作者: 舞鹤Roc | 来源:发表于2023-02-19 10:21 被阅读0次

如果前后端不分离,是不是就不会有跨域问题呢?😭

一、同源策略

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

\color{#FF0000}{同源策略是浏览器的行为} ,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,\color{#FF0000}{服务器响应了} ,但是无法被浏览器接收。

我们在简书首页请求百度,可以发现跨域的报错blocked by CORS policy

fetch(new Request('https://www.baidu.com', {
    method: 'POST',
    headers: {},
    body: "param1=value1&param2=value2"
})).then((resp) => { console.log(resp) })
跨域报错

同源策略,它是由Netscape提出的一个著名的安全策略。只有当 protocol(协议)、domain(域名)、port(端口)三者一致时才是同源,后面的请求路径、请求参数、锚点可以不一致。

二、跨域资源共享(CORS)

当我们在响应头中添加了允许跨域header,浏览器就不会拒绝请求了。

  • Access-Control-Allow-Origin: 允许哪些ip或域名可以跨域访问
  • Access-Control-Max-Age: 表示在多少秒之内不需要重复校验该请求的跨域访问权限
  • Access-Control-Allow-Methods: 表示允许跨域请求的HTTP方法,如:GET,POST,PUT,DELETE
  • Access-Control-Allow-Headers: 表示访问请求中允许携带哪些Header信息,如:Accept、Accept-Language、Content-Language、Content-Type

三、实际如何解决跨域问题

1、在前端服务解决跨域

1.1 html标签

虽然浏览器对于不符合同源策略的访问是禁止的,但是仍然存在例外的情况,如以下资源引用的标签不受同源策略的限制:

  • html的script标签
  • html的link标签
  • html的img标签
  • html的iframe标签
1.2 JSONP

JSONP 主要就是利用了 script 标签没有跨域限制的这个特性来完成的。浏览器是允许像 link、img、script 标签在路径上加载一些内容进行请求,是允许跨域的,JSONP 的实现原理就是在 script 标签里面加载了一个链接,去访问服务器的某个请求。但是,\color{#FF0000}{JSONP 有一个限制就是只支持 GET 请求},实际应用中并不推荐。

2、在后端服务解决跨域

2.1 设置HttpServletResponse响应请求头(局部跨域配置)

这是最原始也是最基础的方法。

    @RequestMapping("/cors")
    @ResponseBody
    public String cors(HttpServletResponse response){
        //使用HttpServletResponse定义HTTP返回请求头
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
        return "cors";
    }
2.2 使用CrossOrigin注解(局部跨域配置)

利用SpringMvc提供的CrossOrigin注解,原理同上,只是利用注解切面的方式实现。

    @RequestMapping("/cors")
    @ResponseBody
    @CrossOrigin(origins = "http://localhost:8080", maxAge = 600) 
    public String cors( ){
        return "cors";
    }
2.3 使用CorsFilter进行(全局跨域配置)

一个个的加注解实际开发不可取,所以定义过滤器,实现统一处理,是最常用的手段。

    @Configuration
    public class GlobalCorsConfig {
        @Bean
        public CorsFilter corsFilter() {
            CorsConfiguration config = new CorsConfiguration();
            //开放哪些ip、端口、域名的访问权限,星号表示开放所有域
            config.addAllowedOrigin("*");
            //是否允许发送Cookie信息
            config.setAllowCredentials(true);
            //开放哪些Http方法,允许跨域访问
            config.addAllowedMethod("GET","POST", "PUT", "DELETE");
            //允许HTTP请求中的携带哪些Header信息
            config.addAllowedHeader("*");
            //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
            config.addExposedHeader("*");
    
            //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
            UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
            configSource.registerCorsConfiguration("/**", config);
    
            return new CorsFilter(configSource);
        }
    }
2.4 重写WebMvcConfigurer的addCorsMappings方法(全局跨域配置)

这个也是SpringMvc提供的,相对过滤器性能会更高。

    @Configuration
    public class GlobalCorsConfig {
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurer() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")    //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
                            .allowedOrigins("*")    //开放哪些ip、端口、域名的访问权限
                            .allowCredentials(true)  //是否允许发送Cookie信息 
                            .allowedMethods("GET","POST", "PUT", "DELETE")     //开放哪些Http方法,允许跨域访问
                            .allowedHeaders("*")     //允许HTTP请求中的携带哪些Header信息
                            .exposedHeaders("*");   //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                }
            };
        }
    }

3、在 Nginx 等反向代理解决跨域

原本浏览器是访问 localhost:8080/api请求后端服务的接口,现在让 Nginx 监听 8080 端口,把请求转发到后端服务新的端口 80801 上。Nginx 接收到后端服务的响应后,添加相关的 CORS 头部返回给浏览器,就不会报跨域的问题。
同理,转发对应的protocol(协议)、domain(域名)也是可行的。

events {}
http {
   server {
     listen          8080;
     server_name     localhost;
     location / {
       if ($request_method = 'OPTIONS') {
         add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1:8080';
         add_header 'Access-Control-Allow-Methods' 'PUT,DELETE';
         add_header 'Access-Control-Allow-Headers' 'Test-CORS, Content-Type';
         add_header 'Access-Control-Max-Age' 1728000;
         add_header 'Access-Control-Allow-Credentials' 'true';
         add_header 'Content-Length' 0;
         return 204;
       }
   
       #Access-Control-Allow-Origin是必须的,其他可选
       add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1:8080';  
       add_header 'Access-Control-Allow-Credentials' 'true';
   
       proxy_pass http://127.0.0.1:80801;
       proxy_set_header Host $host;
     }
   }
}

4、Websocket

webSocket本身不存在跨域问题,所以我们可以利用webSocket来进行非同源之间的通信。

5、浏览器允许跨域

我们使用命令行输入下面指令打开Chrome,此时浏览器会提醒:您使用的是不受支持的命令行标记:--disable-web-security。稳定性和安全性会有所下降

open -n "/Applications/Google Chrome.app" --args --disable-web-security  --user-data-dir=yourdir

我们同样的在简书主页请求百度,却可以正常返回了,不会报跨域错误。

浏览器运行跨域

参考链接

https://developer.aliyun.com/article/841748
https://juejin.cn/post/6844903991558537223

相关文章

网友评论

      本文标题:你又遇到跨域问题了吗

      本文链接:https://www.haomeiwen.com/subject/xmsikdtx.html