我的ajax跨域方案

我的移動端web app前后端分離后,前端頁面的靜態(tài)資源從后端分離,交由cdn加速昔榴,而后端也不再處理頁面渲染妓肢,只提供業(yè)務數(shù)據(jù)供前端通過ajax獲取捌省。
雖然這帶來了喜聞樂見的跨域問題,但是現(xiàn)代瀏覽器都通過XMLHttpRequest對象實現(xiàn)了對CORS的原生支持碉钠,我們只需要注意有限幾點就可以優(yōu)雅得跨域取數(shù)據(jù)纲缓。

服務器設置允許跨域

瀏覽器發(fā)送的跨域請求都會有一個Origin頭部,服務器需要根據(jù)這個頭部信息來判斷是否為合法跨域喊废,如果接受這個跨域請求祝高,需要在響應時在Access-Control-Allow-Origin頭部回發(fā)相同的源信息。如果服務器的響應沒有Access-Control-Allow-Origin頭部污筷,或信息與源信息不匹配工闺,瀏覽器會駁回請求。

以Node.js的express為例:

var app = require('express')();
app.use(function(req, res, next) {
    var origin = req.header('origin');

    // 指定域名的跨域
    // if(!/baidu|qq|alibaba/.test()) return next();

    // 允許跨域
    res.header("Access-Control-Allow-Origin", origin);
    // 允許攜帶票據(jù)
    res.header("Access-Control-Allow-Credentials", true);

    // 允許跨域自定義的 Header
    res.header("Access-Control-Allow-Headers", "Content-Type");
    next();
});

簡單請求

簡單請求是指能夠滿足以下條件的跨域請求:

  1. 請求方法僅限于:
    GET
    HEAD
    POST

  2. 設置的請求頭僅限于:
    Accept
    Accept-Language
    Content-Language
    Content-Type

  3. Content-Type的值僅限于:
    application/x-www-form-urlencoded
    multipart/form-data
    text/plain

詳情參考

另外:
Webkit will force any cross-origin request to be preflighted simply if you register an onprogress event handler.

預請求(Preflighted requests)

對于不滿足上面簡單請求條件的跨域請求,姑且稱“復雜請求”陆蟆,瀏覽器發(fā)送前會先向服務器自動發(fā)送一個OPTIONS請求 以確保復雜請求是可以正常發(fā)出的雷厂。服務器需要作出與簡單請求類似的響應。
以Node.js的express為例:

// enable pre-flight
app.options('*', function(req, res) {
    // pre-flight可被緩存的秒數(shù)
    res.header('Access-Control-Max-Age', 3);
    res.end();
});

使用cors簡化服務器端配置

以上一叠殷、三中基于express的設置可用通過引入cors簡化:

var app = require('express')();
// 配置跨域
//
var cors = require('cors');
app.use(cors({
    origin: /baidu|qq|alibaba/,
    credentials: true,
    maxAge: 60*60*24*100 // pre-flight時效改鲫,100天
}));
app.options('*', cors());// enable pre-flight

瀏覽器端發(fā)起跨域請求

傳統(tǒng) Ajax 指的是 XMLHttpRequest(XHR),但是XMLHttpRequest 是一個設計粗糙的 API林束,不符合關注分離(Separation of Concerns)的原則钩杰,配置和調(diào)用方式非常混亂诊县,而且基于事件的異步模型寫起來也沒有現(xiàn)代的 Promise友好讲弄。
Fetch API 是基于 Promise 設計,可以很好的解決XHR的問題依痊。但是Fetch自身也存在一些問題避除,我從使用到放棄的過程中遇到的最大問題是,不原生支持請求超時胸嘁,而通過setTimeout模擬只是“自欺欺人”瓶摆,很容易出現(xiàn)瀏覽器端被模擬超時中止掉之后,服務器端仍然處理了請求性宏。

后來我就通過XHR模擬Fetch:

// fetch風格的ajax post
function _post(url, data, withCredentials = false) {
    return new Promise((resolve, reject) => {
        var req = new XMLHttpRequest();
        // 啟動一個post群井,到指定接口,異步
        req.open('post', url, true);
        // 默認情況下毫胜,瀏覽器發(fā)起的跨域請求不提供票據(jù)(cookie等)
        // 當服務器設置了允許攜帶票據(jù)后书斜,還要在瀏覽器端設置攜帶票據(jù)
        req.withCredentials = withCredentials;

        // 請求數(shù)據(jù)格式統(tǒng)一為json
        // 為了符合跨域的Simple requests要求
        // 借助Content-Language與服務器協(xié)商替代
        // 'Content-Type': 'application/json; charset=utf-8'
        req.setRequestHeader('Content-Language', 'json');
        data = JSON.stringify(data) || null;

        // 設置超時
        req.timeout = timeout;
        req.ontimeout = function() {
            reject({ message: '請求超時' });
        };

        // xhr.readystate = 4
        req.onload = function() {
            let result = req.responseText;

            // 某些情況(如服務器宕機)會導致訪問req.status報錯
            if(req.status < 400) {
                if(/json/.test(req.getResponseHeader('Content-Type'))) {
                    result = JSON.parse(result);
                }

                resolve(result);
            }
            else reject({ message: result, status: req.status });
        };

        // Network error
        req.onerror = function() {
            reject({ message: '網(wǎng)絡異常' });
        }

        req.send(data);
    });
}

server端借助header的Content-Language處理json:

// config body parser
//
var bodyParser = require('body-parser');
// parse application/json
// Content-Type 為 application/json 的 cors request 不符合 simple requests,會觸發(fā) pre-flight
// 約定:Content-Type: application/json 用 content-language 含有 "json" 代替
app.use(bodyParser.json({ type: function(req) {
    return
        /json/.test(req.headers['content-type']) ||
        /json/.test(req.headers['content-language']);
} }));
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酵使,一起剝皮案震驚了整個濱河市荐吉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌口渔,老刑警劉巖样屠,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缺脉,居然都是意外死亡痪欲,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門攻礼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來业踢,“玉大人,你說我怎么就攤上這事秘蛔≡赏觯” “怎么了傍衡?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵深员,是天一觀的道長负蠕。 經(jīng)常有香客問我,道長倦畅,這世上最難降的妖魔是什么遮糖? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮叠赐,結果婚禮上欲账,老公的妹妹穿的比我還像新娘。我一直安慰自己芭概,他們只是感情好赛不,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著罢洲,像睡著了一般踢故。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惹苗,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天殿较,我揣著相機與錄音,去河邊找鬼桩蓉。 笑死淋纲,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的院究。 我是一名探鬼主播洽瞬,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼业汰!你這毒婦竟也來了片任?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤蔬胯,失蹤者是張志新(化名)和其女友劉穎对供,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氛濒,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡产场,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了舞竿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片京景。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖骗奖,靈堂內(nèi)的尸體忽然破棺而出确徙,到底是詐尸還是另有隱情醒串,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布鄙皇,位于F島的核電站芜赌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏伴逸。R本人自食惡果不足惜缠沈,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望错蝴。 院中可真熱鬧洲愤,春花似錦、人聲如沸顷锰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽官紫。三九已至肛宋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間万矾,已是汗流浹背悼吱。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留良狈,地道東北人后添。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像薪丁,于是被迫代替她去往敵國和親遇西。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • ajax作為前端開發(fā)必需的基礎能力之一严嗜,你可能會使用它粱檀,但并不一定懂得其原理,以及更深入的服務器通信相關的知識漫玄。在...
    蕭玄辭閱讀 812評論 0 0
  • 本文詳細介紹了 XMLHttpRequest 相關知識茄蚯,涉及內(nèi)容: AJAX、XMLHTTP睦优、XMLHttpReq...
    semlinker閱讀 13,613評論 2 18
  • Ajax和XMLHttpRequest 我們通常將Ajax等同于XMLHttpRequest渗常,但細究起來它們兩個是...
    changxiaonan閱讀 2,227評論 0 2
  • 時間:2016-2-13 20:00-22:00 編號:2016044 書名:《愛上跑步的13周》【加】伊恩·邁克...
    中文ID閱讀 178評論 0 1
  • 本杰明·布拉頓(Benjamin Bratton)在TED上發(fā)表過一篇演講,"What's Wrong With ...
    瘋狂的石頭哥閱讀 718評論 1 10