网络编程-跨域资源共享 CORS

1.什么是同源策略?

如果两个 URL 的 protocol、port 和 host 都相同的话,则这两个 URL 是同源。同源策略对Web应用程序具有特殊意义,因为Web应用程序广泛依赖于HTTP cookie来维持用户会话,所以必须将不相关网站严格分隔,以防止丢失数据泄露。
值得注意的是同源策略仅适用于脚本,这意味着某网站可以通过相应的HTML标签访问不同来源网站上的图像、CSS和动态加载脚本等资源。而跨站请求伪造就是利用同源策略不适用于HTML标签的缺陷。

2.跨域资源共享 CORS

跨域资源共享(英语:Cross-origin resource sharing,缩写:CORS),用于让网页的受限资源能够被其他域名的页面访问的一种机制。

通过该机制,页面能够自由地使用不同源(英语:cross-origin)的图片、样式、脚本、iframes以及视频。一些跨域的请求(特别是Ajax)常常会被同源策略所禁止的。跨源资源共享定义了一种方式,为的是浏览器和服务器之间能互相确认是否足够安全以至于能使用跨源请求。比起纯粹的同源请求,这将更为自由和功能性的(functionality ),但比纯粹的跨源请求更为安全。

3.预检请求

需预检的请求要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

不会触发CORS预检的请求称为简单请求,满足以下所有条件的才会被视为简单请求

1)使用GET、POST、HEAD其中一种方法

2)只使用了如下的安全首部字段,不得人为设置其他首部字段

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type 只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

4.CORS相关字段

  • Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
  • Access-Control-Allow-Headers:表明服务器允许请求中携带的头信息字段。值为逗号分割的列表。
  • Access-Control-Allow-Credentials:该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
  • Access-Control-Allow-Methods:该字段必需,用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。
  • Access-Control-Max-Age:该字段可选,用来指定本次预检请求的有效期,单位为秒。在此期间,不用发出另一条预检请求。

5.Golang实现跨域

客户端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>XMLHttpRequest CORS</title>
</head>
<body>
    <h2>XMLHttpRequest CORS</h2>

    <button id="send">发送POST(application/x-www-form-urlencoded)</button>
    <button id="sendJSON">发送POST(application/json)</button>
    <script type="application/javascript">
        document.getElementById('send').onclick = function (evt) {
            let xhr = new XMLHttpRequest();
            xhr.open("POST", "http://127.0.0.1:8080/index", true)
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
            xhr.setRequestHeader("x-Custome-Header", "true")

            let params = new URLSearchParams()
            params.append("name", "dazuo")
            params.append("age", "24")
            xhr.send(params)
        }

        document.getElementById('sendJSON').onclick = function (evt) {
            let xhr = new XMLHttpRequest();
            xhr.open("POST", "http://127.0.0.1:8080/index", true)
            xhr.setRequestHeader("Content-Type", "application/json")
            xhr.setRequestHeader("x-Custome-Header", "true")

            let postData = JSON.stringify({
                name: "dazuo",
                age: 24
            })
            xhr.send(postData)
        }
    </script>
</body>
</html>

服务端

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func HTTPCORS() {
	http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
		header := w.Header()
		header.Set("Access-Control-Allow-Origin", "*")
		header.Set("Access-Control-Allow-Headers", "x-Custome-Header,Content-Type")
		header.Set("Access-Control-Allow-Credentials", "false")
		header.Set("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT,OPTIONS")
		header.Set("Access-Control-Max-Age", "5")
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusNoContent)
		}
		reqBody, _ := ioutil.ReadAll(r.Body)
		fmt.Printf("RequestURI: %s, Methods: %s, ReqBody: %s\n", r.RequestURI, r.Method, reqBody)
		_, _ = w.Write([]byte("welcome !"))
	})

	err := http.ListenAndServe("127.0.0.1:8080", nil)
	if err != nil {
		log.Panic(err)
	}
}

6.参考资料

1.同源策略 - 维基百科

2.跨域资源共享 - 维基百科

3.跨域资源共享 CORS 详解 - 阮一峰的网络日志

posted @ 2020-08-23 21:49  MarsZuo  阅读(240)  评论(0编辑  收藏  举报