No ‘Access-Control-Allow-Origin‘ header is present跨域及解決
No ‘Access-Control-Allow-Origin‘ header is present
- 1 瀏覽器的限制
- 2 跨域
- 3 瀏覽器發(fā)送的是 XHR (XMLHttpRequest)請(qǐng)求
當(dāng)以上三個(gè)條件都滿足時(shí)瀏覽器會(huì)拋出跨域請(qǐng)求異常(記住是瀏覽器拋出的異常,和服務(wù)端沒(méi)太大關(guān)系),在講跨域請(qǐng)求解決方案前先了解幾個(gè)問(wèn)題。
http請(qǐng)求中,哪些是常見(jiàn)的簡(jiǎn)單請(qǐng)求,哪些是非簡(jiǎn)單請(qǐng)求
常見(jiàn)的簡(jiǎn)單請(qǐng)求:請(qǐng)求方法為:GET ,HEAD,POST,請(qǐng)求header里面無(wú)自定義頭,Content-Type為以下幾種:text/plain multipart/form-data application/x-www-form-urlencoded
常見(jiàn)的非簡(jiǎn)單請(qǐng)求 :請(qǐng)求方法為:put delete的ajax請(qǐng)求,發(fā)送json格式的ajax請(qǐng)求,帶自定義頭的ajax請(qǐng)求
瀏覽器在發(fā)送跨域請(qǐng)求時(shí)候,會(huì)有哪些過(guò)程
如果是簡(jiǎn)單請(qǐng)求,瀏覽器會(huì)先發(fā)送請(qǐng)求,然后判斷服務(wù)器返的返回頭中是否支持跨域請(qǐng)求,否則拋出跨域異常
如果是非簡(jiǎn)單請(qǐng)求,瀏覽器會(huì)先發(fā)出OPTIONS請(qǐng)求方法的檢測(cè)命令,判斷服務(wù)器是否支持跨域請(qǐng)求,如果支持則發(fā)送真正的請(qǐng)求,如果不支持則拋出跨域異常,因此一個(gè)非簡(jiǎn)單請(qǐng)求每次會(huì)發(fā)送兩個(gè)請(qǐng)求,后面跨域解決方案會(huì)講到緩存OPTIONS預(yù)檢請(qǐng)求
跨域解決方案

方案1:禁用瀏覽器跨域校驗(yàn),即允許跨域訪問(wèn),(這種方案不可取,不可能讓所有的瀏覽器設(shè)置允許跨域訪問(wèn))
谷歌瀏覽器禁用跨域校驗(yàn): 創(chuàng)建一個(gè)快捷方式發(fā)送到桌面 ,快捷方式--》右鍵---》屬性頁(yè)面中的目標(biāo)輸入框里追加 --disable-web-security --user-data-dir=C:\Program Files (x86)\Google\Chrome\Application (注意:--user-data-dir的值就是瀏覽器安裝目錄。)不一定生效
方案2:采用jsonp方式,需要后臺(tái)和前臺(tái)同時(shí)改動(dòng)代碼,
1 前臺(tái)需要設(shè)置callback參數(shù),如果使用的是jquery ajax 那么dateType屬性設(shè)置為jsonp,jquery框架會(huì)自動(dòng)設(shè)置參數(shù)名為callback的請(qǐng)求參數(shù),也可以通過(guò)jsonp屬性修改jsonp請(qǐng)求參數(shù)名,其他js框架根據(jù)具體api使用,
2 后臺(tái)接收到callback參數(shù)后認(rèn)為是jsonp請(qǐng)求,需要返回jsonp格式,普通json請(qǐng)求返回的content-Type是application/json,而jsonp返回的是application/javascript,同時(shí)也證明了jsonp請(qǐng)求服務(wù)端返回的是js腳本
3 jsonp請(qǐng)求參數(shù)名前后約定需要相同,例如jquery默認(rèn)使用的是callback
弊端:jsonp 需要前后端都去修改代碼,且jsonp是通過(guò)動(dòng)態(tài)創(chuàng)建script腳本發(fā)送請(qǐng)求,僅支持 GET方法,jsonp發(fā)出的請(qǐng)求不是xhr請(qǐng)求,也是能解決跨域的原因

方案3:服務(wù)端解決跨域問(wèn)題
通過(guò)編寫(xiě)filter在response對(duì)象中添加響應(yīng)頭,告訴瀏覽器允許跨域訪問(wèn),* 號(hào)代碼允許所有的請(qǐng)求域名,所有的請(qǐng)求方法跨域訪問(wèn)
@WebFilter("/*")
public class CORSFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
// 告訴瀏覽器允許所有的域訪問(wèn)
// 注意 * 不能滿足帶有cookie的訪問(wèn),Origin 必須是全匹配
// resp.addHeader("Access-Control-Allow-Origin", "*");
// 解決辦法通過(guò)獲取Origin請(qǐng)求頭來(lái)動(dòng)態(tài)設(shè)置
String origin = request.getHeader("Origin");
if (StringUtils.hasText(origin)) {
resp.addHeader("Access-Control-Allow-Origin", origin);
}
// 允許帶有cookie訪問(wèn)
resp.addHeader("Access-Control-Allow-Credentials", "true");
// 告訴瀏覽器允許跨域訪問(wèn)的方法
resp.addHeader("Access-Control-Allow-Methods", "*");
// 告訴瀏覽器允許帶有Content-Type,header1,header2頭的請(qǐng)求訪問(wèn)
// resp.addHeader("Access-Control-Allow-Headers", "Content-Type,header1,header2");
// 設(shè)置支持所有的自定義請(qǐng)求頭
String headers = request.getHeader("Access-Control-Request-Headers");
if (StringUtils.hasText(headers)) {
resp.addHeader("Access-Control-Allow-Headers", headers);
}
// 告訴瀏覽器緩存OPTIONS預(yù)檢請(qǐng)求1小時(shí),避免非簡(jiǎn)單請(qǐng)求每次發(fā)送預(yù)檢請(qǐng)求,提升性能
resp.addHeader("Access-Control-Max-Age", "3600");
chain.doFilter(request, resp);
}
}方案4:Spring框架提供了跨域解決方案
spring提供了 @CrossOrigin注解用戶解決跨域問(wèn)題,同時(shí)支持全局配置
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}方案5 服務(wù)端通過(guò)ngnix解決跨域問(wèn)題
location /{
?? ??? ??? ?proxy_pass http://localhost:8080/;
?? ??? ? ??
?? ??? ??? ?#告訴瀏覽器允許跨域訪問(wèn)的方法
?? ??? ??? ?add_header Access-Control-Allow-Methods *;
?? ??? ??? ?# 告訴瀏覽器緩存OPTIONS預(yù)檢請(qǐng)求1小時(shí)
?? ??? ??? ?add_header Access-Control-Max-Age 3600;
?? ??? ??? ?#允許帶有cookie訪問(wèn)
?? ??? ??? ?add_header Access-Control-Allow-Credentials true;
?? ??? ??? ?#注意 * 不能滿足帶有cookie的訪問(wèn),Origin 必須是全匹配,這里通過(guò)變量獲取
?? ??? ??? ?add_header Access-Control-Allow-Origin $http_origin;
?? ??? ??? ?#設(shè)置支持所有的自定義請(qǐng)求頭
?? ??? ??? ?add_header Access-Control-Allow-Headers $http_access_control_request_headers;
?? ??? ??? ?#如果預(yù)檢請(qǐng)求,則返回成功,不需要轉(zhuǎn)發(fā)到后端
?? ??? ??? ?if ($request_method = OPTIONS){
?? ??? ??? ??? ?return 200;
?? ??? ??? ?}
?? ??? ?}方案6 客戶端通過(guò)nginx隱藏跨域
#轉(zhuǎn)發(fā)全部以/api開(kāi)頭的請(qǐng)求到web服務(wù)器
???location??/api
???{
? ? ? ? proxy_pass?http://127.0.0.1:8080/api;
???}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Feign 集成 Hystrix實(shí)現(xiàn)不同的調(diào)用接口不同的設(shè)置方式
這篇文章主要介紹了Feign 集成 Hystrix實(shí)現(xiàn)不同的調(diào)用接口不同的設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java讀取resources中資源文件路徑以及jar中文件無(wú)法讀取的解決
這篇文章主要介紹了Java讀取resources中資源文件路徑以及jar中文件無(wú)法讀取的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
Java實(shí)現(xiàn)微信公眾號(hào)發(fā)送模版消息
大家好,本篇文章主要講的是Java實(shí)現(xiàn)微信公眾號(hào)發(fā)送模版消息,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01
ObjectInputStream 和 ObjectOutputStream 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
ObjectInputStream 和 ObjectOutputStream 的作用是,對(duì)基本數(shù)據(jù)和對(duì)象進(jìn)行序列化操作支持。本文給大家詳細(xì)介紹了ObjectInputStream 和 ObjectOutputStream的相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧2017-05-05
Spring定時(shí)任務(wù)中@PostConstruct被多次執(zhí)行異常的分析與解決
這篇文章主要給大家介紹了關(guān)于Spring定時(shí)任務(wù)中@PostConstruct被多次執(zhí)行異常的分析與解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
詳解SpringMVC組件之HandlerMapping(一)
這篇文章主要介紹了詳解SpringMVC組件之HandlerMapping(一),HandlerMapping組件是Spring?MVC核心組件,用來(lái)根據(jù)請(qǐng)求的request查找對(duì)應(yīng)的Handler,在Spring?MVC中,有各式各樣的Web請(qǐng)求,每個(gè)請(qǐng)求都需要一個(gè)對(duì)應(yīng)的Handler來(lái)處理,需要的朋友可以參考下2023-08-08
Spring容器的創(chuàng)建過(guò)程之如何注冊(cè)BeanPostProcessor詳解
關(guān)于BeanPostProcessor 各位一定不陌生,今天整理的這篇文章總結(jié)了如何注冊(cè)BeanPostProcessor,文中有非常詳細(xì)的圖文示例,需要的朋友可以參考下2021-06-06
java 學(xué)習(xí)筆記(入門(mén)篇)_多選擇結(jié)構(gòu)switch語(yǔ)句
在java中為多路分支選擇流程專門(mén)提供了switch語(yǔ)句,switch語(yǔ)句根據(jù)一個(gè)表達(dá)式的值,選擇運(yùn)行多個(gè)操作中的一個(gè),感興趣的朋友可以了解下2013-01-01

