
我相信如果你寫過前后端分離的web應用程式,或者寫過一些ajax請求呼叫,你可能會遇到過CORS錯誤,
- CORS是什么?
- 它與安全性有關嗎?
- 為什么要有CORS?它解決了什么目的?
- CORS是怎樣運行的?
如果您有這些問題,那么這篇文章非常適合您,
一、什么是CORS?
要了解什么是CORS(Cross-Origin Resource Sharing:跨站資源共享),首先我們需要了解什么是同源策略Same Origin Policy(SOP),SOP是所有的現代瀏覽器都具備的安全措施,它不允許從一個加載的js腳本和資源的Origin域與另一個Origin域進行互動,換句話說,如果您的網站是www.example.com,則您無法向www.test.com發出XHR請求,
那么SOP有什么用?如果沒有同源策略的限制,你想想會發生什么? 比如:您已經登錄到微博,并且不小心打開了一個惡意網站,該網站可以向微博發出請求,并從您微博登錄的會話中提取個人資訊,這顯然是巨大的安全問題,為了防止這種情況,在瀏覽器中實施同源策略的限制,實際上,服務器并沒有意識到在瀏覽器端發生的這一切,您仍然可以使用curl或postman發出相同的請求,并且一切回應正常,因為這些工具上沒有SOP,
如果說SOP是限制跨源訪問的一種方式,那么CORS是一種繞過SOP限制并允許您的前端向服務器提出合法請求的方法, 如果您的服務端的確是存在跨域的情況(實際上對于現代分布式應用,這很常見),由于SOP限制您的客戶端將無法向多節點跨域服務器發出xhr請求,救星就出現了,CORS使我們能夠以安全且可管理的方式做到跨域請求,突破同源策略的限制,
二、同源策略的源(Same Origin Policy的Origin)
源由三部分組成:協議,hostip(域)和埠,例如
http://example.com/xxx/index.html和http://example.com/yyy/index.html是同源,http://example.com:80和http://example.com(對于http默認埠為80)是同源,- 由于協議不同,
http://example.com/app1和https://example.com/app2是不同的源, http://example.com,http://www.example.com由于域名不同,也是不同的源- 非常要注意的是
http://localhost和http://127.0.0.1是不同的源
同源策略就是:不允許不同的ip、埠、協議的應用在瀏覽器內進行互相資源共享、請求呼叫,
三、CORS如何運作?
CORS規范允許服務器向瀏覽器回傳一些HTTP Headers,瀏覽器可以基于這些HTTP Headers來決定是否突破SOP的限制,最主要的一個HTTP Headers是Access-Control-Allow-Origin,
//目標服務允許所有的網站對其進行跨域訪問
Access-Control-Allow-Origin: *
//目標服務允許特定的網站對其進行跨域訪問
Access-Control-Allow-Origin: https://example.com
CORS有兩種型別的請求:“simple”簡單請求和“preflight”預檢請求,根據請求方法的不同由瀏覽器確定使用哪種請求,
simple簡單請求:
如果符合以下所有條件,則API請求被視為簡單請求:
- API方法是以下方法之一:GET,POST或HEAD,
Content-Type請求頭包含:application/x-www-form-urlencoded,multipart/form-data,text/plain
這兩個條件將構成大多數簡單請求的用例,但是可以在此處找到更詳細的簡單請求條件串列,
如果您的API請求被視為simple簡單請求,這個請求就可以直接被發送給服務器,服務器使用CORS HTTP Headers進行回應,瀏覽器將檢查Access-Control-Allow-Origin后決定這個請求是否可以突破同源策略的限制,進行下一步的處理,
preflight預檢請求:
如果您的API請求不滿足成為簡單請求的標準(最常見不滿足簡單請求標準的Content-Type值為application/json),則瀏覽器將在發送實際請求之前發出預檢請求,
舉一個例子,我們嘗試使用GET請求https://example.com/status,Content-Type是application/json,所以瀏覽器認為它不符合一個簡單請求的標準,因此瀏覽器會在發出實際請求之前發出預檢請求,這個預檢請求是使用HTTP的 OPTIONS方法發出的:
curl --location --request OPTIONS 'http://example.com/status' \
--header 'Access-Control-Request-Method: GET' \
--header 'Access-Control-Request-Headers: Content-Type, Accept' \
--header 'Origin: http://test.com'
上面的curl就是模擬預檢請求,實際作用是:瀏覽器希望告訴服務器,我的實際請求將使用HTTP GETmethod進行呼叫,Content-Type與Accept作為HTTP headers,這個請求是從https://test.com發起的,服務器回應此請求:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, HEAD, POST
Access-Control-Allow-Headers: Content-Type, Accept
Access-Control-Allow-Origin:允許發出請求的源,或者*可以從任何來源發出請求,(即允許跨域的源)Access-Control-Allow-Methods:允許的以逗號分隔的HTTP方法串列,(即允許跨域的HTTP方法)Access-Control-Allow-Headers:允許發送的HTTP headers串列,
瀏覽器收到服務端的預檢請求回應之后,在我們的示例中服務器回應*可以從任何來源發出請求,因此現在瀏覽器將再次訪問https://example.com/status,使用GET方法(不再是OPTIONS方法),瀏覽器將不再限制該請求的發出與回應資料的接收,
如果預檢請求回應的Origin是特定的Access-Control-Allow-Origin: http://domain.com,瀏覽器將出現Cross-Origin Request Blocked錯誤,因為服務器端預檢結果只允許http://domain.com發出跨域請求,不允許其他應用向我發出跨域請求,
四、如何處理CORS錯誤
我們現在知道什么是CORS及其作業原理,后面的事情其實就簡單了,從上面的內容我們需要注意的是,對CORS的完全控制權在服務器,即服務器可以允許或禁止源的跨域訪問,所以說跨域問題的處理一般都在服務端進行,不同的服務端的處理HTTP 請求頭的代碼是不一樣的,當然也可以不用寫代碼,比如:nginx、haproxy設定,但是萬變不離其宗:最終都是對HTTP Headers進行重寫,
我就簡單的舉幾個例子:
比如Servlet處理跨域
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*"); //解決跨域訪問報錯
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
chain.doFilter(req, resp);
}
比如Spring MVC配置
@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //添加映射路徑,“/**”表示對所有的路徑實行全域跨域訪問權限的設定
.allowedOrigins("*") //開放哪些ip、埠、域名的訪問權限
.allowCredentials(true) //是否允許發送Cookie資訊
.allowedMethods("GET","POST", "PUT", "DELETE") //開放哪些Http方法,允許跨域訪問
.allowedHeaders("*") //允許HTTP請求中的攜帶哪些Header資訊
.exposedHeaders("*"); //暴露哪些頭部資訊(因為跨域訪問默認不能獲取全部頭部資訊)
}
};
}
}
歡迎關注我的博客,里面有很多精品合集
- 本文轉載注明出處(必須帶連接,不能只轉文字):字母哥博客,
覺得對您有幫助的話,幫我點贊、分享!您的支持是我不竭的創作動力! ,另外,筆者最近一段時間輸出了如下的精品內容,期待您的關注,
- 《手摸手教你學Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《實戰前后端分離RBAC權限管理系統》
- 《實戰SpringCloud微服務從青銅到王者》
- 《VUE深入淺出系列》
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/191688.html
標籤:Java
