0.前言
CORS(Cross-Origin Resource Sharing)是一個用於處理跨域問題的W3C標準,本文將介紹什麼是跨域,引起跨域的同源策略,什麼是CORS,CORS的工作過程,請求方式以及與它有關的header,最後是java使用例子代碼。
1.什麼是跨域?
瀏覽器從一個域名的網頁請求另一個域名的資源時,域名,端口,協議任意一個不同都是跨域請求。(需要注意域名和域名對應的ip也屬於跨域)
2.什麼是同源策略?
在Web瀏覽器中,允許某個網頁腳本訪問另一個網頁的數據,但前提是這兩個網頁必須有相同的協議,主機名和端口號,一旦兩個網站滿足上述條件,這兩個網站被認爲同源。此策略可防止某個網頁上的惡意腳本通過該網頁的文檔對象模型訪問另一個網頁上的敏感數據,但是僅適用於腳本,不適用於HTML標籤。
3.什麼是CORS?
CORS是一種基於HTTP 頭的機制,該機制通過允許服務器標示除了它自己以外的其它origin(域,協議和端口),允許第一個資源所在的域之外的另一個域請求web頁面上的受限資源。尤其是Ajax請求,在默認情況下是被同源安全策略禁止的。CORS定義了一種瀏覽器和服務器可以交互的方式,以確定允許跨源請求是否安全。它比純粹的同源請求允許更多的自由和功能,但比簡單的允許所有跨源請求更安全。整個CORS通信過程,都是瀏覽器自動完成的,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加頭信息,有時會多一次請求,但用戶不會有感覺,因此實現CORS通信的關鍵在服務器,只要服務器實現了CORS接口,就可以進行跨源通信。
4.CORS的工作過程
對於可以修改數據的Ajax和HTTP請求方法(通常爲GET以外的HTTP方法或者用於某些MIME類型的POST使用),規範要求瀏覽器預先發送請求,使用HTTP OPTIONS請求方法從服務器請求支持的方法,在得到服務器的“批准”後,使用實際的HTTP請求方法發送實際請求。服務器還可以通知客戶端“憑據”(包括Cookies和HTTP身份驗證數據)是否應隨請求一起發送。
5.CORS請求
CORS請求分爲簡單請求和預檢請求,上圖中發送的真實請求爲簡單請求,發送真實請求前需進行的OPTIONS請求爲複雜請求。
①簡單請求
概念:當請求方式爲HEAD,GET或POST並且HTTP頭信息僅包含Accept,Accept-Language,Content-Language,Last-Event-ID,Content-Type,其中Content-Type僅限三個值,包括application-x-www-form-urlencoded,multipart/form-data,text-plain。(這樣設計是爲了兼容form表單,因爲表單一直可以發送跨域請求。)
例子:加入用戶訪問http://www.example.com,並且跨域獲取http://service.example.com的用戶信息。與CORS兼容的瀏覽器將嘗試向service.example.com進行跨域請求,具體如下:
//瀏覽器添加一個額外的Origin頭,值爲爲父頁面提供服務的域,併發送GET請求 Origin: http://www.example.com //在service.example.com域的服務將返回帶Access-Control-Allow-Origin頭,其值表示允許訪問的域或者返回錯誤頁面,表示服務器不準跨域請求。 Access-Control-Allow-Origin: http://www.example.com Access-Control-Allow-Origin: * //通配符表示允許所有
[注:“*”的值很特殊,因爲它不允許請求提供憑據,這意味着它不允許在跨域請求中發送HTTP身份驗證,客戶端SSL證書或Cookie。在CORS體系結構中,Access-Control-Allow-Origin頭是由外部web服務設置的(service.example.com),而不是原始的web應用服務(www.example.com)設置的]
②預檢請求
概念:除了上面簡單請求的情況外都要先進行預檢請求,通過後再發送真實請求。
例子:
//www.example.com域上的服務發出OPTIONS預檢請求 OPTIONS / Host: service.example.com Origin: http://www.example.com //如果service.example.com接受該操作,則響應如下: Access-Control-Allow-Origin: http://www.example.com Access-Control-Allow-Methods: PUT, DELETE //之後www.example.com將發送真實請求,若不接受,將會對OPTIONS請求響應錯誤。
6.與CORS有關的頭
①請求頭
Origin
說明:該字段必須,指示了請求來自於哪個站點。該字段僅指示服務器名稱,並不包含任何路徑信息
語法:Origin: ""
Origin: <scheme> "://" <host> [ ":" <port> ]
示例:Origin: http://www.example.com
Access-Control-Request-Method
說明:該字段必須,用於預檢請求告訴服務器哪些HTTP方法在實際請求是將被使用
語法:Access-Control-Request-Method: <method>
示例:Access-Control-Request-Method: POST
Access-Control-Request-Headers
說明:用於預檢請求告訴服務器在真正的請求中會採用哪些頭
語法:Access-Control-Request-Headers: <header-name>, <header-name>, ...
示例:Access-Control-Request-Headers: X-PINGOTHER, Content-Type
②響應頭
Access-Control-Allow-Origin
說明:該字段必須,用於指定該響應是否被允許與給定的域共享
語法:Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: <origin>
示例:Access-Control-Allow-Origin:* --表示允許所有資源訪問
Access-Control-Allow-Origin:http://www.example.com --表示允許http://www.example.com訪問
Access-Control-Allow-Credentials
說明:該字段可選。值爲布爾值,表示是否允許發送Cookie,默認情況下,Cookie不包括在CORS請求之中。
語法:Access-Control-Allow-Credentials:true
Access-Control-Expose-Headers
說明:該字段可選,用於列出哪些頭部可以作爲響應的一部分暴露給外部。默認情況下有七種簡單響應頭部可以暴露給外部,包括:Cache-Control,Content-Language,Content-Length,Content-Type,Expires,Last-Modified,Pragma,Access-Control-Max-Age,Access-Control-Allow-Methods,Access-Control-Allow-Headers
語法:Access-Control-Expose-Headers: <header-name>, <header-name>, ...
示例:Access-Control-Expose-Headers: Content-Length
Access-Control-Max-Age
說明:該字段可選,表示預檢請求的返回結果(即Access-Control-Allow-Method和Access-Control-Allow-Headers提供的信息)可以被緩存多久,即多久可以不用發送預檢請求,若爲-1則禁用,表示每次都請求都必須發送預檢請求。
語法:Access-Control-Max-Age: <delta-seconds>
示例:Access-Control-Max-Age: 600
Access-Control-Allow-Methods
說明:該字段必須,在對預檢請求的應答中明確了客戶端所要訪問的資源允許使用的方法或方法列表。
語法:Access-Control-Allow-Methods: <method>, <method>, ...
示例:Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers
說明:如果請求包括Access-Control-Request-Headers字段,則該字段必須,表明服務器支持的所有header,不限於預檢中請求發送的字段還可能有自定義的。
語法:Access-Control-Allow-Headers: <header-name>[, <header-name>]*
Access-Control-Allow-Headers: *
示例:Access-Control-Allow-Headers: X-Custom-Header, Upgrade-Insecure-Requests
7.java操作
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; // 這裏填寫你允許進行跨域的主機ip httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); // 服務器允許的header httpServletResponse.setHeader("Access-Control-Allow-Headers", "origin, content-type, accept, authorization"); // 允許的訪問方法 httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH"); // Access-Control-Max-Age 用於 CORS 相關配置的緩存 httpServletResponse.setHeader("Access-Control-Max-Age", "1209600"); // 是否允許發送cookie httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; if (null != httpRequest && "OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) { return; } filterChain.doFilter(servletRequest, httpServletResponse); }