這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
單頁應用中,非同步請求資料會受到同源政策限制。
只有當
協議、
連接埠、和
網域名稱都相同的頁面,則兩個頁面具有相同的源。只要網站的 協議名protocol、 主機host、 連接埠號碼port 這三個中的任意一個不同,網站間的資料請求與傳輸便構成了跨域調用,會受到
同源策略的限制。
不僅僅是傳統的ajax,基於promise的axios和fetch也會受到限制。解決方案有很多,這裡簡述一下使用golang搭建一個簡單的代理服務。
proxy
用代理實現跨域請求的原理是
DomainA用戶端(瀏覽器) ==> DomainA伺服器 ==> DomainB伺服器 ==> DomainA用戶端(瀏覽器)
在頁面的同源瀏覽器搭建一個代理服務,頁面請求資料發至同原始伺服器後,由同原始伺服器轉寄到目標伺服器,同時等待響應並將響應轉寄回頁面。
實際上,在一些前端架構中,如vue.js,提供了簡易的代理服務以供測試。在服務端採用相同的配置,可以非常方便的從開發環境轉向生產環境。
httprouter
httprouter是基於golang提供的http包之上封裝的非常輕便的http架構。
HttpRouter is a lightweight high performance HTTP request router (also called
multiplexer or just
mux for short) for Go.
使用httprouter可以非常方便的解析url,添加handler。
go get github.com/julienschmidt/httprouter
主函數內添加要代理的地址和處理函數。
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的方式訪問我們的Proxy 位址
查看log
2018/02/22 11:33:07 /github/login/oauth/access_token => https://github.com/login/oauth/access_token