常用的跨域解决方案有 JSONP 和 CORS, spingboot 2.0 开始不推荐使用 JSONP。
1 CORS
1.1 属性含义
属性 | 含义 |
---|---|
value | 指定所支持域的集合, 表示所有域都支持,默认值为 。这些值对应于 HTTP 请求头中的 Access-Control-Allow-Origin |
origins | @AliasFor(“value”),与 value 属性一样 |
allowedHeaders | 允许请求头中的 headers,在预检请求 Access-Control-Allow-Headers 响应头中展示 |
exposedHeaders | 响应头中允许访问的 headers,在实际请求的 Access-Control-Expose-Headers |
methods | 支持的 HTTP 请求方法列表,默认和 Controller 中的方法上标注的一致。 |
allowCredentials | 表示浏览器在跨域请求中是否携带凭证,比如 cookies。在预检请求的 Access-Control-Allow-Credentials |
maxAge | 预检请求响应的最大缓存时间,单位为秒。在预检请求的 Access-Control-Max-Age 响应头中展示 |
1.2 实现方法
1) CrossOrigin 注解
在 Spring Boot 中为我们提供了一个注解 @CrossOrigin 来实现跨域,这个注解可以加在类或者方法上。
@Controller
public class HomeController {
@GetMapping("/xxx")
@ResponseBody
@CrossOrigin
public String xxx() {
return "xxx";
}
}
2)实现 WebMvcConfigurer 接口
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(168000)
.allowedHeaders("*");
}
}
3)过滤器
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
2 Jsonp
spingboot2.0 已不支持 JSONP
通过 jsonp 调用,对格式重新封装,解决前端跨域。
如:请求http://xxxx?&callback=exec
, 那么返回的jsonp格式为exec({"code":0, "message":"success"});
。
继承AbstractJsonpResponseBodyAdvice
,加入@ControllerAdvice
注解,basePackages 标识要被处理的 controller。
@ControllerAdvice(basePackages = "xxx.controller")
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
private final String[] jsonpQueryParamNames;
public JsonpAdvice() {
super("callback", "jsonp");
this.jsonpQueryParamNames = new String[]{"callback"};
}
@Override
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType, MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
//如果不存在callback这个请求参数,直接返回,不需要处理为jsonp
if (ObjectUtils.isEmpty(servletRequest.getParameter("callback"))) {
return;
}
//按设定的请求参数处理返回结果为jsonp格式
for (String name : this.jsonpQueryParamNames) {
String value = servletRequest.getParameter(name);
if (value != null) {
MediaType contentTypeToUse = getContentType(contentType, request, response);
response.getHeaders().setContentType(contentTypeToUse);
bodyContainer.setJsonpFunction(value);
return;
}
}
}
}```