今天遇到了一個跨域請求登錄驗證的問題。所以有了嘗試跨域的機會。
具體情景是,有一個登錄界面寫在名叫cas的站點上,但是相關的登錄驗證的后台接口是寫在名叫earth的站點。
首先的反應是使用jsonp,但是jsonp只能get請求,而且一旦跨域會有權限問題(這個下面會說),更主要的是jsonp那種類似hack的寫法總讓我覺得別扭。當然最主要的是后台用stringMVC已經實現了CORS。
CORS是一種跨域資源共享的方式,和ajax實際上是沒什么區別的,相對應的RESTFUL方法們都是可以的,實現方式上是有區別的。
這次就先總結下比較簡單的,用GET發一個郵箱地址,讓后台驗證這個郵箱是否可用,返回true或者false。
首先先寫一個客戶端,這個客戶端是用webstorm默認的方式起的,域名應該是localhost:63342
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="cors">send cors</button> </body> <script> var cors=document.querySelector('#cors'); cors.onclick=function () { var xhr=new XMLHttpRequest(); xhr.open('GET','http://localhost:3001/getName',true); xhr.withCredentials=true; xhr.onload=function (data) { console.log(data); }; xhr.send(null); } </script> </html>
這個頁面就是點擊一個按鈕向3001端口發送一個GET請求,可以看到除了xhr.withCredentials=true;以外和ajax沒什么區別,CORS基本上就是個服務端技術。另外提一句,在高程三上說需要在請求頭上寫一句Origin:XXXX來告訴服務端你的源信息,但是實際上我測試的時候發現即使不寫,瀏覽器也會自動把這句加到請求頭里。
var express=require('express');
var url=require('url');
var app=express();
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:63342');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Credentials','true');
next();
};
app.use(allowCrossDomain);
app.get('/checkEmail',function (req,res,next) {
var queryValue=url.parse(req.url).query;
if(queryValue==='fortunewheel@sina.com'){
res.send(true);
}else {
res.send(false);
}
});
app.listen(3001);
可以看到比較明顯的區別就是多了一個allowCrossDomain的中間件,這個中間件的作用就是向響應頭里寫一些東西。
為什么是響應頭?下面是我的一點理解,不對歡迎指正:
跨域請求需要做處理的原因是同源策略,即協議、域名和端口必須完全相同才能發起請求。而同源策略實際上是瀏覽器行為,因為不做限制的跨域是比較危險的,所以各個瀏覽器都會做跨域限制。對於CORS會向服務端發送一個預請求,服務端寫回響應頭。瀏覽器發現預請求的響應頭是允許自己發送請求的才會發送真正的請求。
下面這一句就是告訴什么站點是被允許的
res.header('Access-Control-Allow-Origin', 'http://localhost:63342');
瀏覽器就會知道服務器是允許這個站點進行跨域訪問的。其實,這就是一個白名單機制。
其他的三條是什么意思百度下就好。稍微提一句,建議在客戶端寫上xhr.withCredentials=true; 對應的服務端也要加上對應的響應頭。不過這樣寫,Access-Control-Allow-Origin就不能寫*來允許所有站點請求,在實際工程上也很少允許所有站點。而這也是jsonp不好的地方,如果向設定請求權限要考慮使用其他方法,不如CORS簡便。
當然,上面說的都是簡單請求的CORS。HEAD GET POST方法下,使用某些請求頭(嗯,傳個json是肯定沒問題)都是簡單請求。
復雜請求的機制和簡單請求不太一樣,有空寫寫個下篇詳細說明下。