再一次折腾跨域问题

简介: 再一次折腾跨域问题

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

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

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

$.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接口,并实现其方法,在请求处理前设置头信息,并放行


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;
}

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

<mvc:interceptos>
  <mvc:interceptor>
    <!--拦截所有-->
    <mvc:mapping path="/*/**"/>
    <bean class="com.datahear.CrossOriginInterceptor"></bean>
  </mvc:interceptor>
</mvc:interceptors>

2. 使用注解 @CrossOrigin

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

@CrossOrigin
@RestController
@RequestMapping("users")
public class AaaController {
}

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


@RestController
@RequestMapping("users")
public class AaaController {
    @CrossOrigin
    @RequestMapping("/getUser")
    public Result getUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ……
    }
}

3. 实现WebMvcConfigurer接口,重写addCorsMappings方法

@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过滤器

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配置:

location ^~/wx
        {
            proxy_pass http://localhost:8082;
        }
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/;
  }


相关文章
|
7月前
|
前端开发 API
uniapp中为什么会出现跨域问题,如何解决
uniapp中为什么会出现跨域问题,如何解决
2661 0
|
1月前
|
JSON 缓存 JavaScript
如何解决跨域问题?
除了上述方法外,还有一些其他的跨域解决方案,如`postMessage` API等,可以根据具体的项目需求和场景选择合适的方法来解决跨域问题。
|
1月前
|
安全 JavaScript 前端开发
跨域问题如何解决
跨域问题是指浏览器同源策略限制了不同域名之间的资源访问。解决方法包括:1. CORS(跨域资源共享):服务器设置Access-Control-Allow-Origin响应头;2. JSONP:利用script标签不受同源策略限制的特点;3. 代理服务器:通过后端代理转发请求。
|
6月前
|
JSON 前端开发 安全
写了几年代码,你将跨域问题弄明白了吗?
互联网发展至今,前端开发者经常面临跨域问题,这是因为浏览器的同源策略限制了不同源的网页之间的数据交互。当尝试从`http://127.0.0.1:14949`访问`http://localhost:3000`的资源时,浏览器会阻止这种请求,因为它缺少“Access-Control-Allow-Origin”响应头,这是CORS(跨域资源共享)机制的要求。
|
7月前
|
JSON 前端开发 JavaScript
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
106 0
|
7月前
|
前端开发 JavaScript 应用服务中间件
前端程序员必须要知道的跨域问题以及解决方法
前端程序员必须要知道的跨域问题以及解决方法
|
7月前
|
Java API
uniapp跨域问题解决办法
uniapp跨域问题解决办法
368 0
Hertz踩坑记录,Hertz-CORS跨域问题
字节跳动开源框架Hertz,可能存在的CORS的跨域问题
|
Java Linux 开发者
撸个反向代理工具,搞一搞JRebel
前言 本地反向代理 服务器反向代理【个人推荐】 IDEA安装JRebel并激活 服务器安装JRebel并激活