web跨域問題CORS


1. 是什么?

同源策略

同源策略是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSRF等攻擊。

所謂同源是指"協議+域名+端口"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。

跨域 (cors)

cross-origin resource sharing:當協議、子域名、主域名、端口號中任意一個不相同時,都算作不同域。

不同域之間相互請求資源,就算作“跨域”。例如:

http://localhost:8080 -> http://localhost:8088

2. 為什么?

瀏覽器攔截

跨域並不是沒有發出請求,其實請求能發出去,服務端收到請求並正常返回結果,只是結果被瀏覽器攔截了。

瀏覽器為了阻止用戶讀取到另一個域名下的內容,攔截了ajax響應。

3. 怎樣解決?

CORS設置頭

只要服務器端設置相應的頭允許跨域即可。

Access-Control-Allow-Origin

根據Reuqest請求頭中的Origin來判斷該請求的資源是否可以被共享。

如果Origin指定的源,不在許可范圍內,服務器會返回一個正常的HTTP回應。瀏覽器發現,這個回應的頭信息沒有包含Access-Control-Allow-Origin字段(該字段的值為服務端設置Access-Control-Allow-Origin的值)便知出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。此時HTTP的返回碼為200,所以 這種錯誤無法通過狀態碼識別。

Access-Control-Allow-Credentials

指定是否允許請求帶上cookies,HTTP authentication,client-side SSL certificates等消息。
如需要帶上這些信息,Access-Control-Allow-Credentials:true並需要在XmlHpptRequest中設置xhr.withCredentials=true

需注意的是,當設置了the credentials flag為true,那么Access-Control-Allow-Origin就不能使用"*"

Access-Control-Max-Age

可選字段,指定了一個預請求將緩存多久,在緩存失效前將不會再發送預請求。

Access-Control-Allow-Methods

作為預請求Response的一部分,指定了真實請求可以使用的請求方式。

Access-Control-Allow-Headers

作為預請求Response的一部分,指定了真實請求可以使用的請求頭名稱(header field names)。

golang實現

CORS需要瀏覽器和服務器同時支持。整個CORS通信過程,瀏覽器是自動完成,而服務器需要手動配置。

golang設置HTTP頭部相當簡單,標准包有現成的方法可以使用。

//https://gitee.com/yuxio/epcforedge.git  
    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
    "golang.org/x/net/http2"

    headersOK := handlers.AllowedHeaders([]string{"X-Requested-With",
        "Content-Type", "Authorization"})
    originsOK := handlers.AllowedOrigins(
        []string{AfCtx.cfg.SrvCfg.UIEndpoint})
    methodsOK := handlers.AllowedMethods([]string{"GET", "HEAD",
        "POST", "PUT", "PATCH", "OPTIONS", "DELETE"})

    AfRouter = NewAFRouter(AfCtx)

    serverCNCA := &http.Server{
        Addr:         AfCtx.cfg.SrvCfg.CNCAEndpoint,
        Handler:      handlers.CORS(headersOK, originsOK, methodsOK)(AfRouter),
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

示例

ajax.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script>
        function loadXMLDoc() {
            var xmlhttp;
            if (window.XMLHttpRequest) {
                xmlhttp = new XMLHttpRequest();
            }
            else {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
                }
            }
            xmlhttp.open("GET", "http://127.0.0.1:9000", true);
            xmlhttp.send();
        }
    </script>
    <title>Document</title>
</head>
<body>
    <h2>cross origin</h2>
    <button type="button" onclick="loadXMLDoc()">請求數據</button>
    <div id="myDiv"></div>
</body>
</html>

8000port.go

package main

import (
    "net/http"
    "html/template"
)

func main(){
    http.HandleFunc("/", Entrance)
    http.ListenAndServe(":8000", nil)
}

func Entrance(w http.ResponseWriter, r *http.Request){
    t, _ := template.ParseFiles("ajax.html")
    t.Execute(w, nil)
}

9000port.go

package main

import (
    "net/http"
    "fmt"
)

func main(){
    http.HandleFunc("/", TestCrossOrigin)
    http.ListenAndServe(":9000", nil)
}

func TestCrossOrigin(w http.ResponseWriter, r *http.Request){
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Add("Access-Control-Allow-Headers", "Content-Type")
    w.Header().Set("Content-Type", "text/plain")
    fmt.Fprintln(w, "hello cros!")
}

如果注釋掉Access-Control-Allow-Origin,不能跨域訪問,報如下錯誤(console):

Access to XMLHttpRequest at 'http://127.0.0.1:9000/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

response Headers:

 

參考:

1. 跨域問題及解決方法 nginx部署 sinksmell  https://github.com/sinksmell/lanblog.git 

2. golang跨域訪問

3. Web開發之跨域與跨域資源共享  jsonp cros

4. 前端常見跨域解決方案(全)  jsonp cors nginx nodejs websocket

5. ajax 廖雪峰 

6. 跨域資源共享 CORS 詳解 阮一峰

7. golang server 跨域解決總結 動態許可跨域,根據不同url實現不同跨域

8. chrome瀏覽器的跨域設置——包括版本49前后兩種設置


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM