JavaScript的跨域訪問方法有很多,不下十種。本文總結的是XMLHttpRequest的跨域訪問。
在JavaScript中,我們可以用XMLHttpRequest訪問服務端應用。但是瀏覽器對這類訪問有一個限制,就是JavaScript所在頁面與所訪問的服務端應用必須屬於同一個域內,也就是同一個IP和端口號內。這就是JavaScript同源策略(Access-Control-Allow-Origin),這樣的限制有益於保證服務的安全性,使得本方服務不會被其他網絡應用所盜用。
然而這也會給自己帶來一些不便,因為即便是同一個網絡應用,也有可能在不同的服務器上呀。那么我想,作為網絡服務的設計者,如此嚴格的定義會使得網絡開發變得非常丑陋。所以設計者還是留下一個活口,就是在服務器端應用定義時,允許部分網段訪問,這就是跨域訪問。
下面以上傳文件為例子解釋XMLHttpRequest的跨域訪問。
如何實現跨域訪問?
XMLHttpRequest的使用總是大同小異,直接上代碼。
1 var form = new FormData(); 2 form.append("upload", fileObj); 3 4 var http = new XMLHttpRequest(); 5 if (http != null) { 6 http.onstatechange = stateHandler; 7 http.open("POST", "host:port/url"); 8 http.send(form); 9 } 10 11 stateHandler : function() { 12 if (this.readyState==4) { 13 if (this.status == 200) { 14 console.log("fileObj uploaded successfully!"); 15 } else { 16 console.log("Origin null is not allowed by Access-Control-Allow-Origin"); 17 } 18 } else { 19 console.log("XMLHttpRequest is not ready"); 20 } 21 }
最關鍵的處理在服務器部分,其實無論是否跨域,服務器都是可以獲取上述請求的。問題的關鍵在於服務器的回應是否能夠返回到瀏覽器。
所以在服務器發送回應的時候,需要添加一個文件頭。
response.setHeader("Access-Control-Allow-Origin","http://js.host");
這個文件頭的第一個參數是允許跨域,第二個參數是接受跨域的服務,上述文件頭說明了服務器信任來自http://js.host的請求。
這樣也就實現了XMLHttpRequest的跨域訪問。
Tricks
在這里,其實與不同的XMLHttpRequest還有一個小小的不同,卻很重要。同域內的XMLHttpRequest訪問通常只有一次請求,而跨域的XMLHttpRequest有兩次。
第一次XMLHttpRequest請求,其method是OPTIONS,並非前文定義的POST。這並不是由JS代碼控制的,而是瀏覽器來完成的操作。其作用是判斷該請求是否能夠被服務器所響應。
第二次XMLHttpRequest請求才是真正的POST請求,包含了上傳的文件內容。
因此在服務器端進行處理的時候,需要判斷這兩次請求,不要錯過了真正的上傳內容。
