前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >再一次折腾跨域问题

再一次折腾跨域问题

作者头像
云原生
发布2022-03-30 20:07:42
4060
发布2022-03-30 20:07:42
举报
文章被收录于专栏:云原生实践云原生实践

跨域问题在前后端分离的开发场景中经常遇到,回想起来自己也已经折腾了数次,本篇文章主要对跨域问题做个记录和总结。

跨域在前端中的报错一般为:

代码语言:javascript
复制
Access to XMLHttpRequest at *** from origin *** has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the request resource.

一、为什么会出现跨域问题

任何一个系统都有着或多或少的规则和限制。跨域问题的来源便是浏览器的同源策略:

同源策略是指:协议相同、域名相同、端口相同。

为什么要有同源策略呢?

试想你登录一家电商网站,该网站肯定会在本地存储一些你的隐私信息,这个时候你又登录另一个网站,如果没有同源策略,该网站就可以直接读取到你在电商网站的隐私信息,这对用户来说是完全不可接受的。

也就说,只要违反了同源策略的任何一种,都是跨域。

现代浏览器给出了限制非同源的三种行为:

  • Cookie、LocalStorage 和 IndexedDB,非同源,不可读写。
  • 网页资源,比如DOM,非同源,不可接触。
  • 发送AJAX请求,非同源,浏览器拒绝响应

二、跨域解决方案

跨域的解决方案有很多种:

一 . 使用Ajax的jsonp

代码语言:javascript
复制
$.ajax({
  url: "http://localhost:8090/crossorigin_test/getList",
  dataType: 'jsonp',
  success: function (data) {
}
})

JSONP 只支持get请求、不支持post请求

二. CORS解决跨域

跨源资源共享 (CORS)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。

CORS整个通信过程都由浏览器自动完成,CORS通信与同源的AJAX请求代码逻辑完全一样,只要服务器实现了CORS接口,浏览器就会自动携带一些附加的请求头信息,从而实现跨源通信,对用户而言是无感知的。

CORS需要浏览器和服务器的支持,CORS已经被现代浏览器广泛采用,因此服务器端的支持是关键。

我们重点看看后端使用Spring如何配置CORS跨域

1. Servlets方式手工设置响应头

创建跨域拦截器实现HandlerInterceptor接口,并实现其方法,在请求处理前设置头信息,并放行

代码语言:javascript
复制
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
   // 设置:Access-Control-Allow-Origin头,处理Session问题
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("P3P", "CP=CAO PSA OUR");
        if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
            response.addHeader("Access-Control-Allow-Methods", "POST,GET,TRACE,OPTIONS");
            response.addHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept");
            response.addHeader("Access-Control-Max-Age", "120");
        }
        // 放行
        return ture;
}

再在配置文件中配置拦截器

代码语言:javascript
复制
<mvc:interceptos>
  <mvc:interceptor>
    <!--拦截所有-->
    <mvc:mapping path="/*/**"/>
    <bean class="com.datahear.CrossOriginInterceptor"></bean>
  </mvc:interceptor>
</mvc:interceptors>
2. 使用注解 @CrossOrigin

在类上加注解,表示类下所有方法都支持跨域请求

代码语言:javascript
复制
@CrossOrigin
@RestController
@RequestMapping("users")
public class AaaController {

}

在方法上加注解,表示该方法支持跨域请求

代码语言:javascript
复制
@RestController
@RequestMapping("users")
public class AaaController {

    @CrossOrigin
    @RequestMapping("/getUser")
    public Result getUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ……
    }
}
3. 实现WebMvcConfigurer接口,重写addCorsMappings方法
代码语言:javascript
复制
@Configuration
public class MvcConfig implements WebMvcConfigurer {

    /**
     * 解决跨域请求
     * @return
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
        .allowCredentials(true)
        .allowedOrigins("*")
        .allowedHeaders("*")
        .allowedMethods("*")
        .maxAge(3600);

        WebMvcConfigurer.super.addCorsMappings(registry);
    }
}
4. 使用CorsFilter过滤器
代码语言:javascript
复制
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    // 当前跨域请求最大有效时长。这里默认30天
    private long maxAge = 30 * 24 * 60 * 60;

    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
        corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
        corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
        corsConfiguration.setMaxAge(maxAge);
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); // 4 对接口配置跨域设置
        return new CorsFilter(source);
    }
 }

三. Nginx反向代理

利用nginx反向代理把跨域问题转为不跨域,支持各种请求方式

直接看nginx配置:

代码语言:javascript
复制
location ^~/wx
        {
            proxy_pass http://localhost:8082;
        }
代码语言:javascript
复制
location /admin/ {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://localhost:8080/;
  }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-03-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 . 使用Ajax的jsonp
  • 二. CORS解决跨域
    • 1. Servlets方式手工设置响应头
      • 2. 使用注解 @CrossOrigin
        • 3. 实现WebMvcConfigurer接口,重写addCorsMappings方法
          • 4. 使用CorsFilter过滤器
          • 三. Nginx反向代理
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档