前文介紹了jsonp跛璧,本文介紹如下另外兩種方法:
- 服務(wù)器端的代理
- cors
解決方法之 - 服務(wù)器端代理
思路如下:
在localhost:3000中的ajax在發(fā)請求時搁料,不是直接請求localhost:4000/getData红柱,而是請求本域的中的接口迎变,例如:localhost:3000/getDataFrom4000,然后在getDataFrom4000路由中去請求localhost:4000/getData。
原來是:
3000.html -----> localhost:4000
用服務(wù)器端的代理則是:
3000.html -----> localhost:3000 -----> localhost:4000
示意圖如下:
背后的原理是:服務(wù)器端與服務(wù)器端之間不存在在跨域的問題只盹。
話多不說辣往,直接上代碼。
兩步走:
第一步:在port3000.js中殖卑,添加一個路由響應(yīng):
const https = require("https"); //額外引入一個https模塊
app.get("/getZhihu",(req,res1)=>{
let url = "https://news-at.zhihu.com/api/4/news/latest";
https.get(url,(res)=>{
let str = "";
res.on("data",(chunk)=>{
str += chunk;
})
res.on('end',()=>{
res1.json(str);
})
})
});
上面的代碼的功能是當(dāng)用戶在瀏覽器中輸入localhost:3000/getZhihu時站削,通過https模塊去請求"https://news-at.zhihu.com/api/4/news/latest"(這是 zhihu公開的一個接口),在請求結(jié)束后孵稽,再返回數(shù)據(jù)许起。
如果你直接去瀏覽器中訪問這個接口的話,你大概會看到如下:
但你是不能直接在ajax中直接訪問的:原因還是前面說的“跨域”菩鲜。
第二步:在3000..html中园细,添加一個按鈕的事件響應(yīng):
$("#btnzhihu").on("click",function(){
console.info("btnzhihu");
$.ajax({
type:"GET",
url:"https://news-at.zhihu.com/api/4/news/latest",
dataType:"json",
success:function(d){
console.log(d)
$("#result").html(JSON.stringify(d));
}
});
})
如果這樣寫的話,就會遇到跨域錯誤接校。你應(yīng)該把url改成下面的這句:
url:"http://localhost:3000/getZhihu",
然后就ok了猛频,效果如下:
解決方法之 - cors
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)蛛勉。它允許瀏覽器向跨源服務(wù)器鹿寻,發(fā)出XMLHttpRequest
請求,從而克服了AJAX只能同源使用的限制诽凌。
CORS需要瀏覽器和服務(wù)器同時支持毡熏。目前,所有瀏覽器都支持該功能侣诵,IE瀏覽器不能低于IE10痢法。
整個CORS通信過程,都是瀏覽器自動完成杜顺,不需要用戶參與疯暑。對于開發(fā)者來說,CORS通信與同源的AJAX通信沒有差別哑舒,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請求跨源幻馁,就會自動添加一些附加的頭信息洗鸵,有時還會多出一次附加的請求,但用戶不會有感覺仗嗦。
因此膘滨,實現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實現(xiàn)了CORS接口稀拐,就可以跨源通信火邓。
以上參考阮老師的文章
cors的解決方案只要做一件事情就是要在服務(wù)器端寫一些代碼,在用戶請求這個資源時,服務(wù)器的響應(yīng)頭中加一個Access-Control-Allow-Origin頭信息字段铲咨。下面我們?nèi)バ薷膒ort4000.js文件躲胳。
app.all('/getData', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next(); //[1]
});
app.get("/getData",(req,res)=>{
let d = require("./data.json");
res.end(d);
});
說明:app.all("/getData")這句就是要加上的代碼。它的功能是在用戶請求localhost:4000/getData時纤勒,先設(shè)置頭信息坯苹,然后next(),繼續(xù)按app.get("/getData")進行具體的業(yè)務(wù)邏輯摇天。
就這樣粹湃,完了。
三種方法的比較
方法 | 優(yōu)點 | 缺點 |
---|---|---|
jsonp | 簡單 | 需服務(wù)器支持泉坐;只能處理get請求为鳄,這一點是由jsonp的實現(xiàn)原理所決定的。 |
服務(wù)器代理 | 靈活 | 相對繁瑣 |
CORS | 簡單get,post 都支持 | 需服務(wù)器支持 |
補充:chrome瀏覽器中的傻瓜跨域
chrome瀏覽器提供了一個插件腕让,如果你開啟這個插件孤钦,則它會幫你解決跨域的問題。
安裝之后记某,
在使用時司训,你開啟它就可以了。當(dāng)然液南,這是只能是在自己的瀏覽器 中使用一下壳猜。
附參考代碼:
https://github.com/fanyoufu/code/tree/master/ajax-cross-domain
(完)