golang跨域访问

假设在站点 http://domain-a.com的某 HTML页面通过 <img>src请求 http://domain-b.com/image.jpg。网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源。出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。
例如,XMLHttpRequestFetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,尤其在开发和测试时,跨域问题会给前端测试带来非常不便。除非使用CORS头文件。
这个CORS(Cross-Origin Resource Sharing,跨域资源共享)W3C的一个工作草案,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。它背后的基本思想是:使用自定义的HTTP头来告诉浏览器,让运行在一个 Origin(包含请求页面的源信息:协议、域名和端口)上的Web应用被准许访问来自不同源服务器上的指定的资源。
比如一个简单请求,它没有自定义的头部,而主体内容是text/plain。在发送请求时,需要给它附加一个额外的Origin头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头信息来决定是否给予响应。例如Origin: http://www.baidu.com
如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部中返回相同的源信息,例如:Access-Control-Allow-Origin:http://www.baidu.com。如果是公共资源,可以将值设置为*。但是如果没有这个头部,或者有这个头部,但源信息不匹配,浏览器就会驳回请求。

具体实现

CORS需要浏览器和服务器同时支持。整个CORS通信过程,浏览器是自动完成,而服务器需要手动配置。golang设置HTTP头部相当简单,标准包有现成的方法可以使用。

完整代码示例

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:8001", 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("templates/ajax.html")
	t.Execute(w, nil)
}

8001port.go

package main

import (
	"net/http"
	"fmt"
)

func main() {
	http.HandleFunc("/", TestCrossOrigin)
	http.ListenAndServe(":8001", 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!")
}

当将TestCrossOrigin接口中的首行注释后,进行访问。我们可以在浏览器控制台看到下图中的内容。
golang跨域访问取消注释后,就可以正常调用端口8001上的接口。
golang跨域访问

参考文章

  1. JavaScript高级程序设计第二十一章