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