pom.xml
org.springframework.boot spring-boot-starter-web org.projectlombok lombok 1.16.14
@Slf4j
@RestController
@RequestMapping("/cross")
public class CrossController {@PostMapping("/request")public String crossRequest(HttpServletRequest request) {log.info("接收到跨域请求参数:{}",request.getParameter("name"));return "Request CrossServer Success";}}
application.properties
server.port=8080
server.servlet.context-path=/crossServer
至此我们就提供了一个接口:http://localhost:8080/crossServer/cross/request
pom.xml
org.springframework.boot spring-boot-starter-web org.projectlombok lombok 1.16.14
@Controller
@RequestMapping("/test")
public class WebController {@RequestMapping(value = "/request")public String request(HttpServletRequest request) {return "/cross";}
}
跨域测试页面
跨域测试
application.properties
server.port=8081
server.servlet.context-path=/crossWebspring.freemarker.request-context-attribute=request
spring.freemarker.charset=UTF-8
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.prefix=/views
至此我们就提供了一个接口:http://localhost:8081/crossWeb/test/request,访问此页面可以打开如下测试页面:

在没有任何跨域处理的情况下,我们点击按钮,发起请求,得到结果如下:
Access to XMLHttpRequest at 'http://localhost:8080/crossServer/cross/request' from origin
'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
POST http://localhost:8080/crossServer/cross/request net::ERR_FAILED 200
| 请求地址 | 说明 | 是否跨域 |
|---|---|---|
| http://www.alian.com/a http://www.alian.com/b | 同域名 | 否 |
| http://www.alian.com/a/b http://www.alian.com/c/d | 同域名不同文件夹 | 否 |
| http://www.alian.com/a https://www.alian.com/a | 同域名不同协议 | 是 |
| http://www.alian.com/a http://www.alian.com:8080/a | 同域名下不同端口 | 是 |
| http://www.alian.com/a http://yun.alian.com/a | 同顶级域名不同二级域名 | 是 |
| http://www.alian.com/a http://www.yang.com/a | 不同域名 | 是 |
| http://www.alian.com/a http://10.130.1.88:80/a | 域名和对应的ip | 是 |
最简单的方式是通过使用注解@CrossOrigin,但是需要注意的是这个注解版本,这个注解是从Spring Framework 4.2 GA开始有的。如果你项目的版本低于这个版本是用不了的。
package com.alian.crossserver.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;@Slf4j
@RestController
@RequestMapping("/cross")
public class CrossController {@CrossOrigin(origins = "*")@PostMapping("/request")public String crossRequest(HttpServletRequest request) {log.info("接收到跨域请求参数:{}",request.getParameter("name"));return "Request CrossServer Success";}}
为了避免方法间相互影响,我们先在我们的方法crossRequest,去除注解@CrossOrigin(origins = “*”),后面也是一样就不一一提示了。
package com.alian.crossserver.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 所有接口.allowCredentials(true) // 是否发送 Cookie.allowedOriginPatterns("*") // 支持域.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法.allowedHeaders("*").exposedHeaders("*");}
}
上面是对全部方法都支持跨域,我们也可以指定某个请求支持跨域,如下:
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/cross/request") // 指定接口.allowCredentials(true) // 是否发送 Cookie.allowedOriginPatterns("*") // 支持域.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法.allowedHeaders("*").exposedHeaders("*");}
}
再没有使用以上方式解决跨域的情况下,我们使用过滤器也可以实现。
package com.alian.crossserver.filter;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 CustomCorsFilter {@Beanpublic CorsFilter corsFilter() {// 创建cors配置对象CorsConfiguration config = new CorsConfiguration();// 支持域config.addAllowedOriginPattern("*");// 是否发送 Cookieconfig.setAllowCredentials(true);// 支持请求方式config.addAllowedMethod("*");// 允许的原始请求头部信息config.addAllowedHeader("*");// 暴露的头部信息config.addExposedHeader("*");// 添加地址映射UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();corsConfigurationSource.registerCorsConfiguration("/**", config);// 返回 CorsFilter 对象return new CorsFilter(corsConfigurationSource);}
}
上面是对所有域名请求都支持跨域,我们也可以指定某个域名,意思就是只有指定域名可以跨域请求。比如:我们只允许http://localhost:8081的跨域请求。
@Configuration
public class CustomCorsFilter {@Beanpublic CorsFilter corsFilter() {// 创建cors配置对象CorsConfiguration config = new CorsConfiguration();// 支持指定域config.addAllowedOriginPattern("http://localhost:8081");// 是否发送 Cookieconfig.setAllowCredentials(true);// 支持请求方式config.addAllowedMethod("*");// 允许的原始请求头部信息config.addAllowedHeader("*");// 暴露的头部信息config.addExposedHeader("*");// 添加地址映射UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();corsConfigurationSource.registerCorsConfiguration("/**", config);// 返回 CorsFilter 对象return new CorsFilter(corsConfigurationSource);}
}
在没有使用以上方式解决跨域的情况下,我们通过Response对象也可以实现跨域。
@Slf4j
@RestController
@RequestMapping("/cross")
public class CrossController {@PostMapping("/request")public String crossRequest(HttpServletRequest request, HttpServletResponse response) {response.setHeader("Access-Control-Allow-Origin", "*");log.info("接收到跨域请求参数:{}",request.getParameter("name"));return "Request CrossServer Success";}}
如果是嫌上述方法在每个方法里都要设置response.setHeader(“Access-Control-Allow-Origin”, “*”),那就可以统一处理返回。可以利用@ControllerAdvice和ResponseBodyAdvice通知完成。
package com.alian.crossserver.advice;import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;@ControllerAdvice // 织入通知
public class ResponseAdvice implements ResponseBodyAdvice {/*** 内容是否需要重写(返回true表示重写)** @param returnType* @param converterType* @return*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}/*** 放回结果前调用** @param body* @param returnType* @param selectedContentType* @param selectedConverterType* @param request* @param response* @return*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,Class selectedConverterType, ServerHttpRequest request,ServerHttpResponse response) {// 设置跨域response.getHeaders().set("Access-Control-Allow-Origin", "*");return body;}}
可能还有些老系统spring版本是Spring Framework 4.2 GA之前的,比如3.X。可能上面有些方式也用不了,比如注解。这里我们可以使用jsonp方式,这里我们先改下我们的前端和后端。
在之前的控制层增加一个接口jsonpRequest
@Slf4j
@RestController
@RequestMapping("/cross")
public class CrossController {@RequestMapping("/jsonpRequest")public String jsonpRequest(HttpServletRequest request, HttpServletResponse response,@RequestParam("callback") String callback) {log.info("1接收到跨域请求参数:姓名:{},年龄:{}",request.getParameter("name"),request.getParameter("age"));log.info("2接收到跨域请求参数:{}",callback);String json="{\"msg\":\"Request CrossServer Success\"}";return callback+"("+ json +")";}
}
这里需要注意的两个点:
对应前端第一种方法是jsonp约定俗成的默认值为callback
test cross
跨域接口测试
所以我的后端接口就有一个参数接收
@RequestParam("callback") String callback
假设你不想用默认的方法,比如方法名占用了,怎么办呢?那就像下面这样自定义方法名:
test cross
跨域接口测试
jsonpCallBack是自定义方法名,你也可以改成其他的名字,记得请求参数,请求地址,及其方法定义,三个一起改哦。
两者的结果如下:

跨域是浏览器的行为,跨域问题其实就是浏览器的同源策略所导致的,所以后端就没有跨域一说了。以上几种跨域解决方法单独用一个就行了,尽量不要混用,以免出现其他重复冲突的问题。还有其他一些通过nginx或者网关等方法都可以解决跨域问题,就不一一介绍了。
上一篇:细粒度图像分类论文研读-2022