單頁應用中,異步請求數據會受到同源政策限制。前端
只有當 協議、 端口、和 域名都相同的頁面,則兩個頁面具備相同的源。只要網站的 協議名protocol、 主機host、 端口號port 這三個中的任意一個不一樣,網站間的數據請求與傳輸便構成了跨域調用,會受到 同源策略的限制。
不單單是傳統的ajax,基於promise的axios和fetch也會受到限制。解決方法有不少,這裏簡述一下使用golang搭建一個簡單的代理服務。vue
用代理實現跨域請求的原理是ios
DomainA客戶端(瀏覽器) ==> DomainA服務器 ==> DomainB服務器 ==> DomainA客戶端(瀏覽器)
git
在頁面的同源瀏覽器搭建一個代理服務,頁面請求數據發至同源服務器後,由同源服務器轉發到目標服務器,同時等待響應並將響應轉發回頁面。github
實際上,在一些前端框架中,如vue.js,提供了簡易的代理服務以供測試。在服務端採用相同的配置,能夠很是方便的從開發環境轉向生產環境。golang
httprouter是基於golang提供的http包之上封裝的很是輕便的http框架。ajax
HttpRouter is a lightweight high performance HTTP request router (also called multiplexer or just mux for short) for Go.
使用httprouter能夠很是方便的解析url,添加handler。shell
go get github.com/julienschmidt/httprouter
主函數內添加要代理的地址和處理函數。axios
func main() { router := httprouter.New() router.GET("/", index) //以post方式訪問/github爲前綴的url時,完整的url會轉化爲參數傳入函數 router.POST("/github/*proxyPath", proxy) log.Fatal(http.ListenAndServe(serverPort, router)) }
func proxy(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { // /github -> remote remote := "https://github.com" // 獲取完整url u := remote + ps.ByName("proxyPath") log.Println(r.URL,"=>",u) // 以現有的request建立新的request req,err := http.NewRequest(r.Method, u , r.Body) /* method url body */ req.Header = r.Header /* header */ client := http.DefaultClient // 發起新的請求 res, err := client.Do(req) if err != nil { w.WriteHeader(404) fmt.Fprint(w, err) return } // 獲取新的body bodyRes,err:=ioutil.ReadAll(res.Body) if err!=nil{ w.WriteHeader(404) fmt.Fprint(w, err) return } // 設置新的header for k, vs := range res.Header { for _, v := range vs { w.Header().Add(k,v) } } // 設置新的cookie for _, value := range res.Request.Cookies() { w.Header().Add(value.Name,value.Value) } // 寫入狀態 w.WriteHeader(res.StatusCode) w.Write(bodyRes) }
特別注意:寫出時必須先設置header再寫出狀態碼和body跨域
以post的方式訪問咱們的代理地址
查看log
2018/02/22 11:33:07 /github/login/oauth/access_token => https://github.com/login/oauth/access_token