高級前端工程師的進階之路 --- 數(shù)據(jù)請求篇

數(shù)據(jù)請求知多少

老鐵們都知道上網(wǎng)是通過瀏覽器發(fā)送HTTP請求券膀,接著服務器后收到請求,發(fā)送資源到瀏覽器谷扣,然后瀏覽器解析靜態(tài)資源(如html土全,css,js腳本)來展示給用戶会涎。(若對HTTP感興趣的裹匙,下期會出一個高級前端進階 ---http透析篇)

那前端開發(fā)人員在開發(fā)中,現(xiàn)有的幾種網(wǎng)絡請求數(shù)據(jù)的方法又有哪些呢末秃?它們又有什么不同呢概页?

下面,我們將聊聊數(shù)據(jù)請求這個話題练慕!let's go

數(shù)據(jù)請求之Ajax

ajax全稱是Asynchronous Javascript and XML (異步的JavaScript和XML)最早出現(xiàn)的發(fā)送后端請求數(shù)據(jù)的技術惰匙,一種在無需重新加載整個網(wǎng)頁的情況下,能夠更新部分網(wǎng)頁的技術铃将,屬于原生的js手段项鬼,核心的使用的是XMLHttpRequest對象,多個請求如果之間有先后順序的話劲阎, 就會出現(xiàn)煩人的callback hell绘盟。

數(shù)據(jù)請求之jQuery Ajax

jQuery Ajax是小胖子John Resig用jQuery對ajax進行底層的封裝。簡單的實現(xiàn)有:.get,.post等悯仙。

$.ajax() 返回的是其內(nèi)部創(chuàng)建的XMLHttpRequest對象龄毡。一般不會使用這個這個函數(shù),除非需要更多的選擇锡垄。

數(shù)據(jù)請求之Axios

axios是需要安裝使用的沦零,支持瀏覽器客戶端,也支持nodejs端使用货岭。不是原生JS蠢终,是一個基于promise的HTTP庫。它的特性是:在瀏覽器中創(chuàng)建XMLHttpRequest茴她,在node.js中創(chuàng)建http請求,支持所有的promise的API程奠,攔截請求和響應丈牢,轉化請求數(shù)據(jù)和響應數(shù)據(jù),取消請求瞄沙,自動轉換JSON數(shù)據(jù)己沛,客戶端支持防御XSRF慌核。

什么是xsrf攻擊呢?

全稱是Cross Site Request Forgery申尼,跨站域請求偽造垮卓,是網(wǎng)絡攻擊的一種,關于網(wǎng)絡攻擊以后會出一篇詳細文章师幕。那這里axios是如何通過客戶端來防御xsrf呢粟按? 這里讓你的每個請求都帶一個從cookie中拿到的key,根據(jù)瀏覽器的同源策略霹粥,偽造的請求是拿不到你cookie的key的灭将,這樣,后臺就可以輕松辨別這個請求是否是用戶在假冒網(wǎng)站上的誤導輸入了后控,采用正確的策略進行回應庙曙。

數(shù)據(jù)請求之Fetch

Fetch是一個現(xiàn)代的概念,等同于XMLHttpRequest浩淘。提供了許多與XMLHttpRequest相同的功能捌朴,但被設計的更有擴展性和高效性,核心在于對HTTP接口的抽象张抄,包括Request,Response砂蔽,Headers,Body欣鳖,以及用于初始化異步請求的global fetch察皇。使fetch可以被使用到更多的應用場景中:無論是service worker,Cache API ,甚至是需要你自己在程序中生成響應的方式泽台。fetch也是基于promise設計的什荣。且代碼結構比ajax簡單多了,參數(shù)和jQuery ajax相似怀酷。但是稻爬,fetch不是對ajax的進行底層封裝,他就是原生的js

數(shù)據(jù)請求詳細說

由淺入深Ajax

通過使用ajax技術蜕依,通過在后臺與服務器進行少量的數(shù)據(jù)交換桅锄,就可以使頁面進行異步更新。這樣做的好處是样眠,可以在不用加載整個網(wǎng)頁的情況下友瘤,對網(wǎng)頁的某個部分進行更新。

Ajax的工作原理

瀏覽器端:發(fā)生某個事件檐束,創(chuàng)建XMLHttpRequest對象辫秧,發(fā)送HttpRequest ---> Internet ---> 在服務器端:處理HttpRequest 創(chuàng)建響應并將數(shù)據(jù)返回瀏覽器 ----> Internet ---> 在瀏覽器端: 使用js處理返回的數(shù)據(jù),顯示到頁面上

  • 什么是XMLHttpRequest被丧?

XMLRequest讓發(fā)送HTTP請求變得非常的容易盟戏。只需要簡單的創(chuàng)建一個本實例對象绪妹,打開一個url,然后發(fā)送這個請求柿究。當傳輸完畢后邮旷,結果的HTTP狀態(tài),以及返回的響應內(nèi)容也可以從請求對象中獲取蝇摸。實例代碼:

function reqListener() {
    console.log(this.responseText);
}
let oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener); //傳輸完畢婶肩,加載的數(shù)據(jù)保存在response中 reqListener是回調(diào)函數(shù)   
oReq.open('GET','http://www.example.org/example.txt',true); //第三個參數(shù) true 意味著是異步請求
oReq.send();
  • 請求類型

通過XMLHttpRequest生成的請求可以有兩種方式來獲取數(shù)據(jù),異步模式和同步模式探入。請求的類型由上述的實例代碼中的open() 方法的第三個參數(shù)async的值來決定的狡孔。如果該參數(shù)是false的話,則該XMLHttpRequest請求以同步模式進行蜂嗽,否則該過程將以異步模式完成苗膝。(在部分新版本的瀏覽器中,主線程上的同步請求已經(jīng)被放棄了)

  • 處理響應

w3c規(guī)范定義了XMLHttpRequest對象的幾種類型的響應屬性植旧。這些屬性告訴客戶端關于XMLHttpRequest返回狀態(tài)的重要信息辱揭。一些處理非文本返回類型的用例可能包含一些下面章節(jié)中描述的操作和分析。

分析操作responseXML屬性:

它是一個只讀值病附,它返回一個包含請求檢索的HTML或XML的Document问窃,如果請求未成功,尚未發(fā)送完沪,或者檢索的數(shù)據(jù)無法正確解析為 XML 或 HTML域庇,則為 null。默認是當作“text / xml” 來解析覆积。當 responseType 設置為 “document” 并且請求已異步執(zhí)行時听皿,響應將被當作 “text / html” 來解析。responseXML 對于任何其他類型的數(shù)據(jù)以及 data: URLs 為 null宽档。

如果使用XMLHttpRequest來獲得一個遠程的XML文檔的內(nèi)容尉姨,responseXML屬性將會是一個由XML文檔解析而來的DOM對象,這很難被操作和分析吗冤。以下是五種主要的分析XML文檔的方式:

1又厉,使用XPath定位到文檔的指定部分。

2椎瘟,手工的解析和序列化XML為字符串或對象覆致。

3,使用XMLSerializer把DOM樹序列化成字符串或文件肺蔚。

4篷朵,如果預先知道XML文檔的內(nèi)容,你可以使用RegExp。如果你用RegExp掃描時受到換行符的影響声旺,你有可能想要刪除所有的換行符。然而段只,這種方法是“最后手段”腮猖,因為如果XML代碼發(fā)生了輕微的變化,該方法將可能失敗赞枕。

解析和操作包含HTML文檔的responseText屬性:

如果使用XMLHttpRequest從服務端獲取到一個HTML頁面澈缺,則所有HTML標記會以字符串的形式存放在responseText屬性里,這樣就使得操作和解析這些HTML標記變得非常的困難炕婶。解析這些標記主要會有以下的三種方式:

1姐赡,XMLHttpRequestresponseXML屬性

2,將內(nèi)容通過fragment.body.innerHTML注入到一個文檔片段中柠掂,并遍歷DOM中的片段项滑。

3,如果預先知道html文檔的內(nèi)容涯贞,可以使用RegExp枪狂。如果你用RegExp掃描時受到換行符的影響,你有可能想要刪除所有的換行符宋渔。然而州疾,這種方法是“最后手段”,因為如果HTML代碼發(fā)生了輕微的變化皇拣,該方法將可能失敗严蓖。

  • 處理二進制數(shù)據(jù)

有時通過XMLHttpRequest也可以發(fā)送和接受二進制內(nèi)容,有很多方法可以強制使用XMLHttpRequest發(fā)送二進制數(shù)據(jù)氧急,利用XMLHttpRequest.overrideMimeType()方法是一個解決方案颗胡,雖然它并不是一個標準方法。

let oReq = new XMLHttpRequest();
oReq.open("GET",url,true);
oReq.overrideMimeType("text/plain;")

在XMLHttpRequest Level2 規(guī)范中新加入了responseType屬性态蒂,使用二進制通信變得更加容易和便捷杭措。

let oReq = new XMLHttpRequest();
oReq.onload = function(e) {
    let arraybuffer = oReq.response; //not responseText
}
oReq.open("GET",url,true)
oReq.responseType = "arraybuffer" //在send之前修改數(shù)據(jù)類型 變?yōu)槎M制類型
oReq.send()
  • 事件監(jiān)測

XMLHttpRequest 提供了各種在請求被處理期間發(fā)生的事件以供監(jiān)聽(如定期進度通知,錯誤處理等)

支持DOM的progress事件 監(jiān)測于XMLHttpRequest傳輸钾恢,遵循web API 進度事件規(guī)范:這些事件實現(xiàn)了ProgressEvent接口手素。

  • 提交表單和上傳文件

XMLHttpRequest的實例有兩種方式來提交表單和上傳文件:

1, 使用Ajax

2,使用FormData API

使用formdata api 是最簡單最快捷的瘩蚪,但是被收集的數(shù)據(jù)無法使用JSON.stringify() 轉換為一個JSON字符串泉懦。

第一種方式是最復雜的但是是最靈活的和最強大的。

由淺入深 jQuery Ajax

實例:

$.ajax({
    url: "/api/getWeather",
    data: {
        zipcode: 97201
    },
    success: function(result) {
        $("#weather-temp").html("<h1>"+result+"</h1>")
    }
})

第一個的Ajax指的是XMLHttpRequest(xhr)疹瘦,最早出現(xiàn)的發(fā)送后端請求崩哩,隸屬于原始的js,核心使用的是XMLHttpRequest對象,多個請求之間如果有先后關系的話邓嘹,會有callback hell 出現(xiàn)酣栈。

jQuery Ajax的出現(xiàn)是對原生xhr的封裝,除此之外還增添了對JSONP(向后端發(fā)送一個請求汹押,得到的是一個函數(shù)的調(diào)用矿筝,在前端頁面上掛載同名函數(shù))的支持,jQuery ajax的出現(xiàn)棚贾,很大程度上解決了數(shù)據(jù)請求的普遍問題窖维,但是隨著現(xiàn)行的react,vue等框架的興起和大批的使用妙痹,以及ES規(guī)范的完善铸史,更多API的更新,使jQuery ajax 開始暴露出弱點:

1怯伊,本身是怎對MVC的編程琳轿,不符合現(xiàn)在的MVVM框架的使用,配置和調(diào)用方式非常的混亂震贵,基于事件的異步模型不太友好利赋。

2,基于原生的XHR開發(fā)猩系,XHR自己的架構都不清晰媚送,也有了Fetch的替代方案的提出。

3寇甸,jQuery整個項目太大塘偎,單純使用ajax要引入整個jQuery,這樣非常不明智拿霉。

默認的情況下吟秩,ajax請求使用的GET方法。如果要使用POST方法绽淘,可以設定Type參數(shù)值涵防。這個選項也會影響data選項中的內(nèi)容如何發(fā)送到服務器(是在地址欄中還是請求體中)。

data選項既可以是一個查詢字符串沪铭,比如key1=value1&key2=value2,也可以是一個映射壮池,比如{ key1: 'value1',key2: 'value2' }。如果使用了映射的形式杀怠,則數(shù)據(jù)再被發(fā)送會被轉換成查詢字符串椰憋。這個處理方式可以通過processData選項為false來回避。若是要發(fā)送一個XML對象給服務器時赔退,這種并不合理橙依。我們也應當改變contentType選項的值证舟,用其他合適的MIME類型來取代默認的application/x-www-form-urlencoded。

var list = {}
$.ajax({
    //請求方式
    type: "POST",
    //請求類型
    contentType: "application/json;charset=UTF-8",
    //請求地址
    url: "http://127.0.0.1/xxx/",
    //數(shù)據(jù),json字符串.
    data: JSON.stringify(list),
    //請求成功
    success: function(result) {
    console.log(rusult)
    },
    error: function(e) {
        console.log(e.status);
        console.log(e.responseText)
    }
})
方法 描述
$.ajax() 執(zhí)行異步AJAX請求
$.ajaxPrefilter() 每個請求發(fā)送之前且被$.ajax()處理之前窗骑,處理自定義Aajx選項或修改已存在選項
$.ajaxSetup() 為將來的AJAX請求設置默認值
$.get() 使用AJAX的HTTP GET請求從服務器加載數(shù)據(jù)
$.getJSON() 使用AJAX的HTTP GET 請求從服務器加載JSON編碼的數(shù)據(jù)
$.getScript() 使用AJAX的HTTP GET 請求從服務器加載并執(zhí)行JavaScript
$.param() 創(chuàng)建數(shù)組或對象的序列化表示形式(可用于AJAX請求的URL查詢字符串)
$.post() 使用AJAX的HTTP POST請求
ajaxComplete() 規(guī)定AJAX請求完成時運行的函數(shù)
ajaxError() 規(guī)定AJAX請求失敗時運行的函數(shù)
ajaxSend() 規(guī)定AJAX請求發(fā)送之前時運行的函數(shù)
ajaxStart() 規(guī)定第一個AJAX請求發(fā)送之前運行的函數(shù)
ajaxStop() 規(guī)定所有的AJAX請求完成時運行的函數(shù)
ajaxSuccess() 規(guī)定AJAX請求成功時運行的函數(shù)
load() 從服務器加載數(shù)據(jù)女责,并把返回的數(shù)據(jù)放置到指定的元素中
serialize() 編碼表單元素集為字符串以便提交
由淺入深Axios

實例:

//get 請求
axios.get('/user?ID=12345')
    .then(function(response) {
    console.log(response)
})
    .catch(function(error) {
    console.log(error)
})
//另一種寫法
axios.get('/user',{
    params: {
        ID: 12345
    }
})
    .then(function (response) {
    console.log(response)
})
    .catch(function (error) {
    console.log(error)
})
//post 請求
axios.post('/users',{
    firstName: 'Fred',
    lastName: 'Flintstone'
})
    .then(function(response) {
    console.log(response)
})
    .catch(function(error) {
    console.log(error)
})
// 執(zhí)行多個并發(fā)請求
function getUserAccount() {
    return axios.get('/user/1234')
}
function getUserPermissions() {
    return axios.get('/user/1234/permissions')
}
axios.all([getUserAccount(),getUserPermissions()])
    .then(axios.spread(function (acct,perms) {
    //請求都執(zhí)行完畢后
}))

在知多少中,我們已經(jīng)提到慧域,Axios本質(zhì)上是對原生XHR的封裝鲤竹,只不過是通過Promise的實現(xiàn)版本,可以用在瀏覽器端和node.js中昔榴,符合最新的ES規(guī)范。

用axios創(chuàng)建請求的時候可以用的配置選項碘橘,只有url是必需的互订。如果沒有指定的method,請求將默認使用get方法痘拆。

axios既提供了并發(fā)的封裝仰禽,體積也較小。也沒有fetch的一些獲取問題纺蛆。目前來看吐葵,這也是尤玉溪在vue中推崇axios的原因。

由淺入深Fetch

Fetch是一個現(xiàn)代的概念桥氏,等同于XMLHttpRequest温峭。提供了許多與XMLHttpRequest相同的功能,但被設計的更有擴展性和高效性.

核心在于對HTTP接口的抽象字支,包括Request,Response凤藏,Headers,Body堕伪,以及用于初始化異步請求的global fetch揖庄。

也提供了一個全局的fetch() 方法,該方法提供了一種簡單欠雌,合理的方式來跨網(wǎng)絡異步獲取資源蹄梢。

請注意,fetch規(guī)范和jQuery ajax() 有兩種方式的不同:

  • 當接收的一個錯誤的HTTP狀態(tài)碼(404)富俄,從fetch() 返回的是Promise 不會被標記為reject禁炒,即便該HTTP響應的狀態(tài)碼是500。它會將promise狀態(tài)標記為resolve(但是會將resolve的返回值得ok屬性設置為false)蛙酪,僅當網(wǎng)絡故障或請求被阻止時齐苛,才會標記為reject。
  • 默認情況下桂塞,fetch不會從服務端發(fā)送或接收任何cookies凹蜂,如果站點依賴于用戶session,則會導致未經(jīng)認證的請求(要發(fā)送cookies,必須設置credentials選項)

實例:

fetch('http://example.com/....json')
    .then(function(response) {
    return response.json();
})
    .then(function(myJson) {
    console.log(myJson)
})

這里我們可以通過網(wǎng)絡獲取一個JSON文件并將其打印到控制臺。最簡單的用法是只提供一個參數(shù)用來指明想fetch() 到的資源路徑玛痊,然后返回一個包含響應結果的promise(一個Response對象)

當然她只是一個HTTP響應汰瘫,不是真正的json。為了獲取JSON的內(nèi)容擂煞,我們需要使用json() 方法(在Bodymixin中定義混弥,被 Request和Response對象實現(xiàn))

fetch() 接受第二個可選參數(shù),一個可以控制不同配置的init對象:

function postData(url,data) {
    return fetch(url,{
        body: JSON.stringify(data),
        cache: 'no-cache',
        credentials: 'same-origin', //include
        headers: {
            'user-agent': 'Mozilla/4.0 MDN Example',
            'content-type': 'application/json'
        },
        method: 'POST',  // GET POST DELETE PUT
        mode: 'cors', // no-cors cors same-origin
        redirect: 'follow',
        referrer: 'no-referrer', 
    })
    .then(response=>response.json())  //轉化為json
}
postData('http://example.com/answer',{answer: 42})
.then(data=>console.log(data))
.catch(error=>console.error(error))

fetch的優(yōu)點:

1对省,語法更加簡潔

2蝗拿,基于標準Promise實現(xiàn),支持async/await

3蒿涎,更加底層哀托,使用的API更加豐富(request,response)

4劳秋,脫離了xhr仓手,是ES規(guī)范里新的實現(xiàn)方式

5,跨域的請求處理

在設置了跨域頭或借助了JSONP的前提下玻淑,瀏覽器的請求是可能隨便跨域嗽冒,但是,fetch中可以設置mode來進行是否跨域补履。

fetch的mode配置項有3個值添坊,如下:

  • same-origin:該模式是不允許跨域的,它需要遵守同源策略干像,否則瀏覽器會返回一個error告知不能跨域帅腌;其對應的response type為basic。意味值請求必須是同源下麻汰。

  • cors: 該模式支持跨域請求速客,顧名思義它是以CORS的形式跨域;當然該模式也可以同域請求不需要后端額外的CORS支持五鲫;其對應的response type為cors溺职。 通過cors方式跨域,后臺配合位喂。

  • no-cors: 該模式用于跨域請求但是服務器不帶CORS響應頭浪耘,也就是服務端不支持CORS;這也是fetch的特殊跨域請求方式塑崖;其對應的response type為opaque七冲。

針對跨域請求,cors模式是常見跨域請求實現(xiàn)规婆,但是fetch自帶的no-cors跨域請求模式則較為陌生澜躺,該模式有一個比較明顯的特點:

該模式允許瀏覽器發(fā)送本次跨域請求蝉稳,但是不能訪問響應返回的內(nèi)容,這也是其response type為opaque透明的原因掘鄙。

這與<img/>發(fā)送的請求類似(通過src請求到一個資源耘戚,也可以通過fetch來請求image),該模式不能訪問響應的內(nèi)容信息操漠;但是它可以被其他APIs進行處理,例如ServiceWorker浊伙。另外,該模式返回的repsonse可以在Cache API中被存儲起來以便后續(xù)的對它的使用嚣鄙,這點對script部服、css和圖片的CDN資源是非常合適的。

總得來說奉芦,fetch在前端跨域的處理上功能非常強大赵抢,原生xhr可望不可及烦却。

參考資料: axios官網(wǎng) / fetch mdn

參考公眾號文章:幾種數(shù)據(jù)請求的介紹,區(qū)別及優(yōu)缺點 --- 全棧者

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末其爵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子摩渺,更是在濱河造成了極大的恐慌,老刑警劉巖剂邮,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摇幻,死亡現(xiàn)場離奇詭異,居然都是意外死亡挥萌,警方通過查閱死者的電腦和手機绰姻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來引瀑,“玉大人狂芋,你說我怎么就攤上這事『┰裕” “怎么了帜矾?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵翼虫,是天一觀的道長。 經(jīng)常有香客問我黍特,道長蛙讥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任灭衷,我火速辦了婚禮次慢,結果婚禮上,老公的妹妹穿的比我還像新娘翔曲。我一直安慰自己迫像,他們只是感情好,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布瞳遍。 她就那樣靜靜地躺著闻妓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掠械。 梳的紋絲不亂的頭發(fā)上由缆,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音猾蒂,去河邊找鬼均唉。 笑死,一個胖子當著我的面吹牛肚菠,可吹牛的內(nèi)容都是我干的舔箭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚊逢,長吁一口氣:“原來是場噩夢啊……” “哼层扶!你這毒婦竟也來了?” 一聲冷哼從身側響起烙荷,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤镜会,失蹤者是張志新(化名)和其女友劉穎奢讨,沒想到半個月后拿诸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡季率,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年飒泻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泞遗。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡史辙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晦毙,到底是詐尸還是另有隱情见妒,我是刑警寧澤甸陌,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布钱豁,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涛目。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沫换。 院中可真熱鬧,春花似錦垮兑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捌浩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尸饺,已是汗流浹背拓诸。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工奠支, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人迈螟。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓答毫,卻偏偏與公主長得像季春,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耘拇,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

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