1.普通跨域请求解决方案

①请求接口添加注解
@CrossOrigin(origins = “http://127.0.0.1:8020“, maxAge = 3600)
说明:origins = “http://127.0.0.1:8020“ origins值为当前请求该接口的域

②通用配置
方案一:
在springboot应用中,使用cors全局配置,需要定义一个配置类CORSConfig,继承 WebMvcConfigurationSupport ,并重写addCorsMappings 方法。

  1. package com.springboot_login.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.servlet.config.annotation.CorsRegistry;
  4. import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
  5. /**
  6. * 设置跨域请求
  7. */
  8. @Configuration
  9. public class CORSConfig extends WebMvcConfigurationSupport {
  10. @Override
  11. protected void addCorsMappings(CorsRegistry registry) {
  12. registry.addMapping("/**").//允许所有的访问请求(访问路径)
  13. allowedMethods("*").//允许所有的请求方法访问该跨域资源服务器
  14. allowedOrigins("*").//允许所有的请求域名访问我们的跨域资源
  15. allowedHeaders("*");//允许所有的请求header访问
  16. super.addCorsMappings(registry);
  17. }
  18. }

注意:在springboot2.X版本后,继承的类是 WebMvcConfigurationSupport

配置的详细信息说明如下:

  • addMapping :配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
  • allowedMethods :允许所有的请求方法访问该跨域资源服务器,如:POST、GET、PUT、DELETE等。
  • allowedOrigins :允许所有的请求域名访问我们的跨域资源,可以固定单条或者多条内容,如:“http://www.aaa.com”,只有该域名可以访问我们的跨域资源。
  • allowedHeaders :允许所有的请求header访问,可以自定义设置任意请求头信息.。

方案二:

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.cors.CorsConfiguration;
  4. import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  5. import org.springframework.web.filter.CorsFilter;
  6. @Configuration
  7. public class CorsConfig {
  8. private CorsConfiguration buildConfig() {
  9. CorsConfiguration corsConfiguration = new CorsConfiguration();
  10. corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使用
  11. corsConfiguration.addAllowedHeader("*"); // 2允许任何头
  12. corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等)
  13. return corsConfiguration;
  14. }
  15. @Bean
  16. public CorsFilter corsFilter() {
  17. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  18. source.registerCorsConfiguration("/**", buildConfig()); // 4
  19. return new CorsFilter(source);
  20. }
  21. }

2.ajax自定义headers的跨域请求

  1. $.ajax({
  2. type:"GET",
  3. url:"http://localhost:8766/main/currency/sginInState",
  4. dataType:"JSON",
  5. data:{
  6. uid:userId
  7. },
  8. beforeSend: function (XMLHttpRequest) {
  9. XMLHttpRequest.setRequestHeader("Authorization", access_token);
  10. },
  11. success:function(res){
  12. console.log(res.code)
  13. }
  14. })

此时请求http://localhost:8766/main/currency/sginInState接口发现OPTIONS http://localhost:8766/main/currency/sginInState 500错误,普通跨域的解决方案已经无法解决这种问题,为什么会出现OPTIONS请求呢?
跨域访问 - 图1

原因
浏览器会在发送真正请求之前,先发送一个方法为OPTIONS的预检请求 Preflighted requests 这个请求是用来验证本次请求是否安全的,但是并不是所有请求都会发送,需要符合以下条件:

  • 请求方法不是GET/HEAD/POST
  • POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain
  • 请求设置了自定义的header字段

对于管理端的接口,我有对接口进行权限校验,每次请求需要在header中携带自定义的字段(token),所以浏览器会多发送一个OPTIONS请求去验证此次请求的安全性。

为何OPTIONS请求是500呢?
OPTIONS请求只会携带自定义的字段,并不会将相应的值带入进去,而后台校验token字段时 token为NULL,所以验证不通过,抛出了一个异常。

那么我们现在来解决这种问题:
① spring boot项目application.yml中添加

  1. spring:
  2. mvc:
  3. dispatch-options-request: true

②添加过滤器配置
第一步:手写RequestFilter请求过滤器配置类此类需要实现HandlerInterceptor类,HandlerInterceptor类是org.springframework.web.servlet.HandlerInterceptor下的。
具体代码实现:

  1. @Component
  2. public class RequestFilter implements HandlerInterceptor {
  3. public boolean preHandler(HttpServletRequest request,HttpServletResponse response,Object handler){
  4. response.setHeader("Access-Control-Allow-Origin", "*");
  5. response.setHeader("Access-Control-Allow-Credentials", "true");
  6. response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
  7. response.setHeader("Access-Control-Max-Age", "86400");
  8. response.setHeader("Access-Control-Allow-Headers", "Authorization");
  9. // 如果是OPTIONS请求则结束
  10. if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
  11. response.setStatus(HttpStatus.NO_CONTENT.value());
  12. return false;
  13. }
  14. return true;
  15. }
  16. }

第二步:手写MyWebConfiguration此类需要继承WebMvcConfigurationSupport。

注意:WebMvcConfigurationSupport是2.x版本以上的,1.x版本为WebMvcConfigurerAdapter 。

  1. @Component
  2. public class MyWebConfiguration extends WebMvcConfigurationSupport{
  3. @Resource
  4. private RequestFilter requestFilter;
  5. @Override
  6. public void addInterceptors(InterceptorRegistry registry) {
  7. // 跨域拦截器
  8. registry.addInterceptor(requestFilter).addPathPatterns("/**");
  9. }
  10. }