09 、手把手教Vue--网络请求

本节大纲

PS:转载请注明出处
作者: TigerChain
地址: https://www.jianshu.com/p/2187be164186
本文出自 TigerChain 简书 手把手教 Vue 系列

教程简介

  • 1、阅读对象
    本篇教程适合新手阅读,老手直接略过
  • 2、教程难度
    初级,本人水平有限,文章内容难免会出现问题,如果有问题欢迎指出,谢谢
  • 3、Demo 地址:https://github.com/tigerchain/vue-lesson
    查看 09 、vue 网络请求

正文

一、Vue 中的网络请求

前几节我们说 vue 的基础知识的时候,说的都是单机应用,在这个抢个红包都要网络的时代,单机根本不成不了事的,而 vue 注重的是写前端组件,对于前后端分离的项目「基于 api 驱动开发」,没有接口「那岂不是扯淡」,这一节我们就来看看在 vue 中如何从服务端拿到数据

在 js 中,我们知道 ajax 的兴起可以说是 js 的一场革命「可以实现异步请求和局部刷新」,使得 Web 站点不仅可以提供静态页面,使得 Web 开发变成可交互的「推动了 Web 技术的发展」

vue 也是基于 js 开发的,那么 vue 中的网络请求有那些呢?

  • 1、豪无疑问 ajax 是完全可以使用的,我们可以自己封装 ajax
  • 2、jquery 必须也要以,当然 jquery 封装了 ajax
  • 3、vue resource「官方不再推荐」
  • 4、axios「官网推荐」
  • 5、自己封装 Promise
  • 6、fetch
  • 7、搭配 async await「ES8 的特性」
  • 8、等等一些其它的请求

二、各个请求的举例

针对以上的请求我们分别说一下,我们就按上面的顺序一个个的来,以下代码我们全部使用 vue-cli 来创建「用法都是在 vue-cli 中的,如果使用 html 引入方式,那就更简单了,引入封装好的 js 即可」

1、ajax 网络请求

题外话

说点题外话,我发现了一个奇怪的现象,我和一些开发人员聊天,甚至是工作好几年的开发人员从来没有自己封装过 ajax「起码要知道底层使用啥实现吧」 ,连 jquery 的 ajax 的源码也没有了解过,基本上都是说不要重复造轮子,有现成的使用即可,不要重复造轮子没有问题,可是不要忘记了还有下句呢,我们起码知道轮子是如何造的,如果使用三方组件或是库,你会「bai」使用「du」,别人也会「bai」使用「du」,你的优势何在?所以我们还是有必要要了解一下 js 原生封装 ajax 的,有点跑题了,我们言归正传

封装 ajax

在这里我们使用自己封装一个 ajax 请求来在 vue 中使用,废话不多说,我们这使用 XMLHttpRequest「就是一个 http 请求对象的封装,简称 XHR」 来封装我们的 ajax 请求

关建步骤

我们使用 vue-cli 来创建项目「这里不说了,以前多次讲过」- customAjaxDemo

1、封装 ajax 代码
# customAjax.js

import Vue from 'vue'
function ajax(options) {
    options = options || {}
    // 默认是 GET 请求
    options.methods = options.methods.toUpperCase() || 'GET'
    options.url = options.url || ''
    // 默认是异步请求
    options.async = options.async || true
    options.data = options.data || {}
    options.success = options.success || function() {}
    options.faile = options.faile || function () {}

    console.log(options)

    let xhr = null

    if(window.XMLHttpRequest) {
        xhr = new XMLHttpRequest()
    }else {
        xhr = new ActiveXObject("Microsoft.XMLHTTP")
    }

    let params = []
    // 遍历请求参数对象,拼接请求参数
    for(let param in options.data){
        params.push(param +'='+options.data[param])
    }
  // 给每个数组后面添加一个 &
    let requestData = params.join('&')
    // 请求类型
    let requestType = options.methods.toUpperCase()
  // 如果是 GET 请求
    if(requestType == 'GET'){
        xhr.open(requestType,options.url+'?'+requestData,options.async)
        xhr.send()
    }else if(requestType == 'POST'){ // 如果是 POST 请求
        xhr.open(requestType,options.url,options.async)
        xhr.setRequestHeader("Content-type",
        "application/x-www-form-urlencoded;charset=utf-8");
        xhr.send(requestData)
    }

    xhr.onreadystatechange = function() {
        if (xhr.readyState==4 && xhr.status==200) {
            options.success(JSON.parse(xhr.responseText))
        }else if(xhr.status!=200) {
            options.faile('request error')
        }
    }
}
// 在 vue 中全局注册 这样可以直接使用不使用 Vue.use() 方式
// Vue.prototype.ajax = ajax
export default {
  install(Vue,options){
    // 在 vue 中全局注册
    Vue.prototype.ajax = ajax
  }
}

由于我们要 vue 中使用,所以我们要使用 vue 把这个 js 暴露出去,可以是供全局使用,也可以在单个组件中引用使用「按需使用」

2、使用 customAjax.js

这里有三种方式使用,通过修改 customAjax.js 中 export 的方式和 vue 全局使用的方式可以有三种方式「修改 customAjax.js 后面的导出方式」

  • (1)、普通的导出方式
普通导出方式

这样想在那个组件中使用,直接 import 进来即可,下面以在 HelloWorld.vue 组件中使用为例,分为两步

导入自定义 ajax

普通导入自定义 ajax

使用自定义 ajax

使用自定义 ajax

在这里我在本地定义一个 json 模拟服务端数据「本地的 json 要放在 static 目录中,由于 vue-cli 只把 static 文件夹暴漏出去,可以看 webpack 配置,放在别的地方会报找不到错误」

运行一把

查看结果

可以看到,我们的请求是成功的

  • (2)、全局使用「引入一次处处使用」

修改 customAjax.js

在这里我们可以使用 Vue.prototype 原型属性可以让每个 Vue 实例中都可以使用它,然后我们在 main.js 中引入它「间接的就达到全局使用的目的」,我们修改 customAjax.js 最后的暴露方式,如下图所示,把其它的注释掉即可

vue-prototype-ajax

修改 HelloWorld.vue 中的 ajax 的使用方式

当然我们还要修改 ajax 的使用方式,由于我们把 ajax 给 Vue 的使用了,所以我们调用的时候使用如下方法

vue-prototype-ajax-use

我们在 HelloWorld.vue 中使用 this.ajax(xxx) 来调用 ajax 方法

ps: 这里注意一下,如果我们在 HelloWorld.vue 中引入 ajax

import ajax from '../js/customAjax' 在 main.js 中不引入,那么就是局部使用,如果我们只在 main.js 中引入,那么就是全局使用了

运行查看结果

查看结果

结果照样出来,没有问题,这样就可以所所有的 vue 的实例中使用 ajax 了

  • (3)、使用 Vue.use(ajax) 来全局使用

我们在使用 Mint-ui 的时候,或是一般三方组件的时候,除了要引入组件之外,还要使用 Vue.use(xxx) 来使用一下,我们还记得在 Mint-ui 那一节我们说过,按需引入 Mint-ui 组件的时候,官方说的 Vue.use(xxx) 组件方法我们验证是使用不了「目前来说,以后版本可能会支持」,只能使用 Vue.component(Component.name, Component) 这种方法来全局注册组件「原因也说过了,就是没有添加能使用 use 的方法」

修改 customAjax.js

对于一个自定义的组件,如果想供全局使用并且可以使用 Vue.use 方法,那么我们就要重写 install 方法,废话不多说,我们直接看代码,还是修改 customAjax.js,如下所示:

vue-install-ajax

修改 main.js

ajax-install-main-js-include

这样我们就要以使用 Vue.use(ajax) 来全局使用 ajax 了,也要使用 this.ajax 来调用

运行查看结果

运行结果和上面一毛一样,这里就不浪费空间来贴图了

2、使用 jquery 中的 ajax 请求

上面我们说了自定义 ajax「基于 XHR来封装的」,下面我们来说说如何在 Vue 中引入 jquery 并且使用 jquery 封装的 ajax

1、初始化项目 jquerydemo

使用 vue-cli 来初始化一个 jquerydemo 的项目「我们轻车熟路了」

2、安装 jquery
yarn add jquery 

ProvidePlugin

我们安装完成了还不能直接使用,要做一些配置「webpack」,当然这里配置有多种方式,我们采用比较常见的一种方式,配置 webpack[图片上传中...(webpack-use-jquery.png-664571-1538906442038-0)]
的 ProvidePlugin,我们来看看 webpack 文档关于 ProvidePlugin 说明:http://www.css88.com/doc/webpack/plugins/provide-plugin/,部分截图如下

webpack-provideplugin

webpack 中配置 jquery

我们来配置一下 webpack.base.conf.js,配置之前,再来看一下 webpack 文档中如何配置 jquery

webpack-use-jquery

修改 webpack.base.conf.js

没有什么好说的,我们依"浮"芦画瓢来配置一下我们的 webpack.base.conf.js 如下所示:

首先我们引入 webapck

var webpack = require("webpack")

再者我们在 module.exports 下添加

配置 webpack.base.config.js 中的 jquery

这样我们就在 vue-cli 中把 jquery 的环境配好了

修改 HelloWorld.vue 核心代码

我们来看一下 HelloWorld.vue 的核心代码,也就是一个 jquery 的 ajax 的使用而已

jquery-ajax-use

没有什么可说的,这里还是使用模拟一个本地的 json 文件来请求,jquery 的 ajax 请求方式这里就不详细的说明了,看文档即可「不是本文说的重点」

运行查看结果

vue-cli 中 jquery ajax 使用

到此 jquery ajax 就说完了,至于 jquery 的其它用法不是我们本节所关心的东西「vue 才不关心什么操作 DOM 呢」

3、vue resource「官方不再推荐了」请求

vue resource 作为曾今 vue 请求推荐的库「虽然现在不推荐了,但是还是值得一试的」,vue-resource 可以通过XMLHttpRequest或JSONP发起请求并处理响应,基本上 ajax 能做的事情,vue-resource 都能做,直接进入正题吧

1、初始化项目 vue-resource-demo

使用 vue-cli 初始化项目 vue-resource-demo

2、安装 vue-resource

进入到 vue-resource-demo 目录中执行

yarn add vue-resource
3、使用 vue-resource

我们在 main.js 中引入 vue-resource 并且使用它「全局组件都可以使用了」

main.js 中使用 vue-resource

这样我们就把 vue-resource 引入到 vue-cli 中了

4、使用 vue-resource 发起请求

我们来修改 HelloWorld.vue,来看看使用的核心代码,上面的 demo 中我们只是使用了本地 json 来模拟请求,现在我们再加一个真实的 api 来请求,我们选的是干货集中营的 api

请求本地 json

vue-resource 请求本地 json

请求干货集中营的福利 api

vue-resource 请求 gnkio 数据

这里 vue-resource 的具体请求的 api 我们不做过多的说明,这个我们看文档直接抄过来使用就可以,更多用法我们看文档即可 https://github.com/pagekit/vue-resource,vue-resource 请求返回的结果是一个 Promise

运行查看结果

vue-resource 请求结果

怎么样,这样我们完成了 vue-resource 的一个请求,vue-resource 可以携带参数,支持 GET、POST 还支持 jsonp ,具体可以看文档「这里说没有什么意义,具体使用看文档即可」,不过 vue 作者不再推荐使用此库了「当然你可以继续使用,这没有什么问题」

4、使用 axios 请求

axios 简单的说就是基于 Promise 的一个同时支持浏览器和 node.js 的 http 请求客户端「基于 xhr 封装,使用 ES 规范的 Promise 来实现」,它不是 vue 的专利「不像 vue-resource」,理论上它可使用在任何前端请求中

比起 vue-resource 来说它更加灵活,并且同时支持浏览器和 node.js,根据作者的原话说的化认为 vue 不应该和 http 请求耦合在一起,应该是单独分离的,所以不再推荐 vue-resourse,我们可以自由选择要使用的 http 请求库,单一职责,这很酷,来看看部分截图

去掉 vue-resource
1、初始化项目 axios-demo

使用 vue-cli 初始化 axios-demo 项目

2、安装 axios
yarn add axios
3、引入 axios

根据我们传统的经验 ,我们在 main.js 中 import axios 再 Vue.use(axios) 一把我们就可以使用了,但是我可以很负责任的告诉你 Vue.use(axios) 不行「它没有重写 install 方法,不信看看源码」,其实这也很容易 理解 axios 又不是 vue 的专属 ajax 请求库,React 中也可以使用,别的前端框架中也可以使用,不可能对每个都单独写一个配合其的使用方法吧。好吧,那我们使用 Vue.prototype 原型属性来暴漏 axios 吧

修改 main.js

在 main.js 中引入 axios

这样我们所有的 vue 实例都可以使用 this.$axios 来请求了

4、添加测试代码

我们还是修改 HelloWorld.vue 来测试 axios「基本上 HelloWorld.vue和上面的一毛一样」,我们只关心方法请求部分「其它可以看源码-会推到 github 上」

axios 请求本地 json

axios 请求本地 json

axios 请求远程 json

axios 请求远程 json

看起来和使用 vue-resource 没有太大区别,只不过返回结果封装不太一样,前者是把结果封装在 response.body 中,后者是封装在 response.data 中「每个库机制不一样,也非常容易理解」,这样我就完成了 axios 的请求,具体的 api 可以看 https://github.com/axios/axios 非常详细「这里就不一一列举了」

运行一把,查看结果

显示 axios 请求结果

怎么样熟悉的界面又一次出来了,还是非常不错的「注意说的不是美女,是 axios」

axios 我们就大概说到这里,还是那句话,你知道有这么个玩意,具体的就去看文档「把文档一个个 api 拿到这里来说,浪费时间和空间」

5、自己封装 Promise

回调地域「callback hell」

开发者都经营过回调地域「callback hell」,下面的伪代码说明一下

// 分别定义三个方法
function getData1(){}
function getData2(){}
function getData3(){}

function request(data,callback){
    request.http(data,function success(res){
            if(res.status=='0001'){
                getData1(res.data,function success(response){
                    if(response.status=='0001'){
                        getData2(response.data,function success(data){
                          getData3(.....)
                        },
                        function error(error){})
                    }
                },
                    function error(err){}
                )
            }
        },
        function error(err){}
    )
}

以上代码全部是伪代码「没有这种方法」就是在一个成功的回调里面调用另一个方法,再在另个成功的方法里面调用另另一个方法「回调地域由此产生,一个方法依赖于另一个运行结果」ajax 典型的存在这种情况,这种代码的可读性和维护性可不就是地域吗?Promise 的出现改善了这一过程

当然对于 Promise 有各种版本的封装,各大类库也都封装自己的 Promise ,但是在 ES6 中 Promise 被统一规范了

Promise 通过链式调用「玩过 rx 的朋友最熟悉,或者知道建造者设计模式的也都太熟悉了」,简单封装一个 Promise 来常常鲜

定义一个 test 方法「符合 Promise 的执行函数」

function test(resolve, reject){
    let i = 0 ;
    setTimeout(function(){
        if(i == 0){
            resolve('cuccess')
        }else {
            reject('error')
        }
    },1000)
}

使用 Promise 来封装

const promise = new Promise(test)
promise.then(function(result){
    var myResult = result+' ok'
    return myResult
}).then(function(myResult){
    console.log(myResult)
}).catch(function(error){
    console.log(error)
})

怎么样,通过 then 操作达到链式调用并且如果想处理一下结果给下一个再 then 即可「以上代码纯粹手写的,不乏有误,但是道理是清楚的」

Promise 是通过构造方法来生成实例的,它依赖两个东西 resolve 和 reject 我们估且认为这分别是成功的回调和失败的回调 promise 就可以任性的 .then 操作了,关于 Promise 简介就到这里,更多可以查看
廖雪峰的官网或是阮一峰的关于 Promise 的介绍「都是不错的入门文章」,下面我们在 vue-cli 中使用自定义 Promise 来完成请求

2、创建 vue-custom-promise-basedxhr 项目

使用 vue-cli 来创建我们的项目,这里基于 XHR 来封装请求

1、自定义 requst.js「在 scr/js 目录下」

const fetchServer = function(url,obj){

  obj = obj || {}
  obj.methods = obj.methods.toUpperCase() || 'GET'
  obj.async = obj.async || true
  obj.data = obj.data || {}

  const promise = new Promise(function(resolve,reject){
    var xhr = null
    if(window.XMLHttpRequest) {
        xhr = new XMLHttpRequest()
    }else {
        xhr = new ActiveXObject("Microsoft.XMLHTTP")
    }
    var params = []
     ..... 省略若干代码,和前面的自定义 ajax 代码一样
    xhr.onreadystatechange = function() {
      if(xhr.readyState == 4){
        if(xhr.status == 200) {
          resolve(JSON.parse(xhr.responseText), this)
        }else {
          reject({code:250,message:"请求失败"}, this)
        }
      }
    }
  })
  return promise
}

export default fetchServer

这样我们就完成了一个使用 Promise 来自定义的一个 ajax 请求

2、在 main.js 的中引入,并供 vue 实例使用

import fetchServer from './js/request.js'
Vue.prototype.fetchServer = fetchServer

3、修改 HelloWorld.vue

本地请求方法

自定义 promise 本地请求方法

远程请求方法

自定义 promise 远程请求方法

以下就完成了自定义 promise 实现 ajax 的调用

4、运行一把

自定义 promise 实现 ajax 结果

怎么样,完美的实现了自定义 ajax 并且解决了回调地域的问题,这就是 Proimse 的优势,其实 fetch 就是帮我们干了个事情,我们定义一个 Promise 的请求是为了演示这一过程「当然 Promise 不仅仅用在请求上,只要是想链式调用都可以使用」

6、使用 fetch 来请求

fetch 是什么东东,fetch 是浏览器提供的原生的 ajax 接口。别急等等,不是 XHR 是浏览器提供的原生的 ajax 接口吗?怎么又出来个 fetch「当然 fetch 就是替代 XHR 的,但是其底层还是 基于 XHR 来封装的」

fetch 本质就是实现 ajax「非 jquery 的 ajax 而是指 XHR」 的封装以及 Promise 的实现,废话不多说,直接来个 demo

1、创建 vue-fetch-demo

使用 vue-cli 创建一个 vue-fetch-demo

2、使用 fetch

由于是浏览器支持的接口「版本支持情况请看」

fetch 支持的浏览器版本

我们可以在 https://caniuse.com/# 网站中查看,React Jquery 等都可以在此网站中查看浏览器版本的支持情况「其中红色是不支持,绿色是支持」

从上图我们可以看到 fetch 对 IE 浏览器支持的不是很友好,但是如果我们如果是开发手机 WebApp 那么问题不大,好了我们开始使用 fetch 吧,fetch 返回的是一个 Promise

直接在 HelloWorld.vue 中添加 fetch api

fetch 请求本地 json

使用 fetch 请求远程服务 api

fetch 请求远程 json

运行查看结果

fetch 请求结果

怎么样还是熟悉的妹子,哦不对熟悉的结果,具体用法可以查看 https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API 说的很详细

哎呀不错哦,又完结了一个请求,别走开我们继续

7、搭配 async await 来完成请求

fetch「Promise的作用」 解决了 ajax 的回调地域问题,但是过多的 .then 让人看来很是不爽,ES2017「ES8」中新增了一个 async await 的一个规范,让异步实现起来 so easy「使用同步的书写方法来写异步,这里不具体展开详述了」 ,我们可以使用 fetch 配合 async await 来实现一个请求

1、创建 async-await-demo 项目

使用 vue-cli 创建 async-await-demo 项目

2、直接修改 HelloWorld.vue

我们修改 HelloWorld.vue 如下所示,先封装一个 async 的 fetch 请求方法

定义一个 async 的方法

定义一个 async 的方法

async 返回的是一个 Promise

async-await 搭配 fetch 请求本地数据

async-await 搭配 fetch 请求本地数据

async-await 搭配 fetch 请求远程数据

async-await 搭配 fetch 请求远程数据

到此我们就把 fetch 拿 async await 封装了,怎么样,调用异步方法如同调用同步方法一样爽,也没有 .then...then 链式方法了,感觉整个世界都清净了

3、运行一把看效果
async-await-fetch 结果

还是熟悉的结果,哦不对「妹子变了,不要关心妹子了」

async-await 使异步是如此的简单,快动手试试吧

三、总结

这节我们说了一下 vue 中的 http 请求方法和类库,并且配合代码都演示了一下,让大家有一个知「一定要行,才能达到知行合一」,并没有具体的对每个请求做具体的说明「由于篇幅有限,大家了解了这些个请求有了一个大体的认识可以自行再深入的了解」,总结一下吧

  • vue 就是一个 View 层,理论上可以和任意的 ajax 请求库搭配使用
  • 本文介绍了 7 种 请求库在 Vue 中的使用「当然不止这 7 种,其它的都类似」
  • 如何选择呢?其它用那种都没有问题,但是可以根据项目需求选择「建议还是使用优大大推荐的 axios」
  • 查看浏览器兼容性可以使用 can i use 网站
  • 建议不要使用 jquery「操作 dom 在 Vue 中多少有一点恶心」 了,如果想用 ajax 直接上 axios
  • 如果想实现异步那么 async-await 轻松搞定

四、参考资料


点赞富一生,转发富五代,更多文章请关注我的微信公号来查阅

公众号:TigerChain

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349