今天打开页面报错,地址是有效的,但浏览器会报 "No 'Access-Control-Allow-Origin' header is present on the requested resource " 错误页面以下: web
这是因为 ajax 跨域请求形成的ajax
因为浏览器同源策略(同源策略,它是由 Netscape 提出的一个著名的安全策略。如今全部支持JavaScript 的浏览器都会使用这个策略。所谓同源是指域名、协议、端口相同),凡是发送请求 url 的协议、域名、端口三者之间任意一与当前页面地址不一样即为跨域。spring
CORS请求(包括预选的带有选项方法)被自动注册到各类 HandlerMapping 。他们处理 CROS 准备请求并拦截 CORS 简单和实际请求,这得益于 CorsProcessor 实现(默认状况下默认DefaultCorsProcessor 处理器),以便添加相关的CORS响应头(如 Access-Control-Allow-Origin )。 CorsConfiguration 容许您指定CORS请求应该如何处理:容许 origins, headers, methods 等。api
a、AbstractHandlerMapping#setCorsConfiguration() 容许指定一个映射,其中有几个CorsConfiguration 映射在路径模式上,好比/api/**。跨域
b、子类能够经过重写AbstractHandlerMapping类的getCorsConfiguration(Object, HttpServletRequest)方法来提供本身的CorsConfiguration。浏览器
c、处理程序能够实现 CorsConfigurationSource 接口(如ResourceHttpRequestHandler),以便为每一个请求提供一个CorsConfiguration。安全
1. 请求接口添加注解 @CrossOrigin(origins = "*", maxAge = 3600)bash
说明:origins = "*" origins 值为当前请求该接口的域mvc
2. 通用配置app
/**
* 跨域请求配置
* @author chendesheng
* @create 2019/9/16 19:07
*/
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",buildconfig());
return new CorsFilter(source);
}
private CorsConfiguration buildconfig(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
}
复制代码
ajax自定义headers的跨域请求
$.ajax({
type:"GET",
url:"http://localhost:8766/main/currency/sginInState",
dataType:"JSON",
data:{
uid:userId
},
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("Authorization", access_token);
},
success:function(res){
console.log(res.code)
}
})
复制代码
此处请求报错:OPTIONS http://localhost:8766/main/currency/sginInState 500
普通跨域的解决方案已经没法解决这种问题,为何会出现OPTIONS请求呢?
缘由:
浏览器会在发送真正请求以前,先发送一个方法为OPTIONS的预检请求 Preflighted requests 这个请求是用来验证本次请求是否安全的,可是并非全部请求都会发送,须要符合如下条件:
对于管理端的接口,我有对接口进行权限校验,每次请求须要在header中携带自定义的字段(token),因此浏览器会多发送一个 OPTIONS 请求去验证这次请求的安全性。
为什么 OPTIONS 请求是500呢?
OPTIONS请求只会携带自定义的字段,并不会将相应的值带入进去,然后台校验 token 字段时 token 为 NULL,因此验证不经过,抛出了一个异常。
如何解决这个异常?
1. spring boot项目application.yml中添加
spring:
mvc:
dispatch-options-request: true
复制代码
2. 添加过滤器配置
第一步:手写 RequestFilter 请求过滤器配置类此类须要实现 HandlerInterceptor 类,HandlerInterceptor 类是 org.springframework.web.servlet.HandlerInterceptor 下的。
具体代码以下:
@Component
public class RequestFilter implements HandlerInterceptor {
public boolean preHandler(HttpServletRequest request,HttpServletResponse response,Object handler){
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "86400");
response.setHeader("Access-Control-Allow-Headers", "Authorization");
// 若是是OPTIONS请求则结束
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
response.setStatus(HttpStatus.NO_CONTENT.value());
return false;
}
return true;
}
}
复制代码
第二步:手写 MyWebConfiguration 此类须要继承 WebMvcConfigurationSupport 。
具体代码实现:
@Component
public class MyWebConfiguration extends WebMvcConfigurationSupport{
@Resource
private RequestFilter requestFilter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 跨域拦截器
registry.addInterceptor(requestFilter).addPathPatterns("/**");
}
}
复制代码
这样就优雅的解决了 ajax 跨域请求的问题。