spring应用中处理cors跨域
关于跨域和CORS相关概念性的问题,这里不多赘述
可以参考阮一峰大神的博客 跨域资源共享 CORS 详解 - 阮一峰的网络日志
Spring提供的注解支持
CrossOrigin
可以标识在类或者方法上
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class CorsController {
@GetMapping
@CrossOrigin(
origins = {"http://localhost"}, // 允许哪些域名来跨域来请求当前资源,可以使用通配符 *
allowedHeaders = {"foo"}, // 允许客户端请求携带的请求头
exposedHeaders = {"foo"}, // 允许客户端访问的响应头
methods = {RequestMethod.GET}, // 允许客户端跨域请求的请求方式
allowCredentials = "true", // 允许客户端请求提交cookie
maxAge = 1600 // 预检测缓存时间
)
public Object cors() {
Map<String,Object> map = new HashMap<>();
map.put("success", Boolean.TRUE);
return map;
}
}
SpringBoot以编码的方式处理跨域
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 WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 需要跨域的uri
.allowedOrigins("http://localhost")
.allowedHeaders("foo")
.exposedHeaders("foo")
.allowedMethods("GET")
.allowCredentials(true)
.maxAge(1600);
}
}
Spring以xml配置的方式处理跨域
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="http://domain1.com, http://domain2.com"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2"
allow-credentials="false"
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="http://domain1.com" />
</mvc:cors>
原生的Servlet可以自定义一个 CorsFilter 来处理跨域
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
@WebFilter(urlPatterns = {"/api/*"},filterName = "corsFilter")
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
httpServletResponse.addHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "foo");
httpServletResponse.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,"foo");
httpServletResponse.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET");
httpServletResponse.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
httpServletResponse.addHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
客户端需要设置,允许携带Cookie
默认的情况下,客户的跨域请求不会携带凭证,需要自己手动编码的方式去设置
XMLHttpRequest
let req = new XMLHttpRequest();
req.withCredentials = true; // 在跨域的情况下,允许携带凭证
req.open('GET','http://localhost:8080');
req.send(null);
req.onreadystatechange = function(){
if(req.readyState == 4 && req.status == 200){
let response = req.responseText;
console.log(response);
}
}
fetch
fetch('http://localhost:8080',{
credentials:'include', // 在跨域的情况下,允许携带凭证
method:'GET',
}).then(response => {
if(response.ok){
response.json().then((json) => {
console.log(json);
});
}
});
千万要注意
如果需要客户端提交Cookie, Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名(Origin
)。否则浏览器会给出异常,跨域失败
String origin = httpServletRequest.getHeader(HttpHeaders.ORIGIN);
httpServletResponse.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);