常用的跨域解决方案有 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"; } }
|
@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(); if (ObjectUtils.isEmpty(servletRequest.getParameter("callback"))) { return; } 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; } } } }
|