今天打開頁面報錯,地址是有效的,但瀏覽器會報 "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 跨域請求的問題。