RESTful架构以及HTTP协议

HTTP协议

HTTP协议描述

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本[1]到本地浏览器的传送协议。HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。

通常,由HTTP客户端发起一个请求,建立一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端发送过来的请求。一旦收到请求,服务器(向客户端)发回一个状态行,比如"HTTP/1.1 200 OK",和(响应的)消息,消息的消息体可能是请求的文件、错误消息、或者其它一些信息。

HTTP是一个客户端和服务器端请求和应答的标准(TCP)。客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它工具的客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求,称这个客户端叫用户代理(user agent)。

在Internet中所有的传输都是通过TCP/IP进行的。HTTP协议作为TCP/IP模型中应用层的协议也不例外。HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。
<center>


15215564008151.jpg -w400

</center>

HTTP默认的端口号为80,HTTPS的端口号为443。

浏览网页是HTTP的主要应用,但是这并不代表HTTP就只能应用于网页的浏览。HTTP是一种协议,只要通信的双方都遵守这个协议,HTTP就能有用武之地。

HTTP特点

  1. 无状态:每次HTTP请求都是独立的,任何两个请求之间没有什么必然的联系。

    协议的状态是指下一次传输可以“记住”这次传输信息的能力。HTTP是不会为了下一次连接而维护这次连接所传输的信息,为了保证服务器内存。

  2. 支持客户/服务器模式。支持基本认证和安全认证。

  3. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

  4. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

  5. HTTP 0.9和1.0使用非持续连接:限制每次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接。HTTP 1.1使用持续连接:不必为每个web对象创建一个新的连接,一个连接可以传送多个对象,采用这种方式可以节省传输时间。

HTTP工作流程

一次HTTP操作称为一个事务,其工作过程可分为四步:

  1. 首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作开始。
  2. 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
  3. 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
  4. 客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。

URI

URI(统一资源标识符)[2]:是一个用于标识某一互联网资源名称的字符串。而这个资源由两个部分确定:资源地址信息(URL)+资源名称信息(URN);

常见的URI格式如下:
http://user:password@host.com:8080/p/a/t/h?query=string&action=add#has

URI组成 含义
http:// 协议名称
user 用户名
password 对应密码
host.com 主机域名地址(异或主机ip地址)
:8080 端口号,默认80
/p/a/t/h 虚拟资源路径
query=string&action=add 参数传递
hash 锚点

HTTP请求与响应

HTTP协议分为请求(Request)与响应(Response)两个部分。

Request——请求

请求内容

请求信息内容包括以下几点:

  • 请求行——request line
    • 请求方法:GET/POST/HEAD/DELETE/PUT/TRACE/OPTIONS。方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Method Not Allowed);当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501(Not Implemented)。HTTP服务器至少应该实现GET和HEAD方法,其他方法都是可选的。此外,除了上述方法,特定的HTTP服务器还能够扩展自定义的方法。

      请求方法 含义
      OPTIONS 返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。
      HEAD 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。该方法常用于测试超链接的有效性,是否可以访问,以及最近是否更新。
      GET 向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在web app中。其中一个原因是GET可能会被网络蜘蛛等随意访问。
      POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
      PUT 向指定资源位置上传其最新内容。
      DELETE 请求服务器删除Request-URI所标识的资源。
      TRACE 回显服务器收到的请求,主要用于测试或诊断。
      CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
      PATCH 用来将局部修改应用于某一资源,添加于规范RFC5789。
    • 请求资源虚拟路径

    • 请求协议

  • 请求头信息——header
    • POST请求头是需要追那个请求主体的长度;如果不注明长度则不会发送请求主体信息;

      content-length:length # length为非零整型数据
      
    • 服务器要想能够解析道POST数据还需要请求头包含数据类型

      content-length:appliacation/x-www-from-urlencoded #数据编码格式
      
    • 格式为key=>value键值对的形式

  • 空行
  • 请求主体信息
    • 使用“&”拼接在一起的key=>value键值对。

【注意】
请求头信息与请求主体信息之间要有一个空行!

请求格式
METHOD /path-to-resource HTTP/Version-number
Header-name-1:Value
Header-name-2:Value

Optional request body
示例
# GET 请求
GET /generate_204 HTTP/1.1 //请求方法 请求虚拟路径 请求协议——请求行
User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.0; MI 5 MIUI/V9.5.1.0.NAACNFA)    //请求头
Host: connect.rom.miui.com  //主机——请求头
Connection: Keep-Alive  //请求头
Accept-Encoding: gzip   //请求头

# POST 请求
POST /quickService/ajax/getServiceCategory.ajax.php HTTP/1.1    //请求行
Host: api1.yaxinzhichuang.com   //请求头
Content-Length: 26  //请求头
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json
Origin: http://api1.yaxinzhichuang.com
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Linux; Android 7.0; MI 5 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://api1.yaxinzhichuang.com/quickService/index.php?action=quickService
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,en-US;q=0.9
Cookie: PHPSESSID=497cde80b0d132a375e872bae9668c41
    // 空行
action=children&parentId=2  //  请求主体信息

Response——响应

响应内容

响应信息内容包括以下几点:

  • 响应行
    • 由HTTP协议版本号
    • 状态码
    • 状态文字
  • 响应头信息
    • 格式为key=>value键值对的形式
  • 空行
  • 响应主体信息(也可能没有)
响应格式
HTTP/Version-number status-code message 
Header-name-1:Value
Header-name-2:Value

Optional response body
示例
## json响应
HTTP/1.1 200 OK     //  响应行
Date: Tue, 20 Mar 2018 16:11:59 GMT //响应行
Server: Apache/2.2.34 (Unix)    //响应行
Expires: Thu, 19 Nov 1981 08:52:00 GMT  //响应行
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0   //响应行
Pragma: no-cache    //响应行
Content-Length: 146 //响应行
Content-Type: text/json;charset=utf-8   //响应行
Proxy-Connection: Keep-alive    //响应行
    //空行
{"Code":100000,"Msg":"操作成功!","Data":{"List":[{"value":"7","text":"电脑系统服务"},{"value":"45","text":"维修"}],"uploadImg":"1"}}    ////响应主体信息,可能是html页面;

API

定义

一些预先定义的函数,目的是能够让应用程序或开发人员能够具有访问指定网络资源的能力,而无需关心访问的远吗以及内部的工作机制细节。

RESTful

为了统一API结构设计规范提出的一种架构标准;然而,RESTful并不是唯一的API架构标准。
REST是“REpresentational State Transfer”的缩写;表现性状态转换;

概念

在RESTful架构中认为所有一切都是资源,每个资源有对应的URI[2]标识;
处理资源的操作有:

操作名称 请求动作名称
GET 获取资源
POST 添加资源
PUT 修改资源(非严格遵行RESTful架构)
UPDATE/PATCH 修改资源(严格遵行RESTful架构)
DELETE 删除资源

客户端通过以上4种http动词,对服务器资源进行操作,实现“表现层状态转化”;

【注意】
只是一种架构而不是标准,提供设计原则和约束条件。
适用于客户端与服务器交互类的软件,这是因为它更加简洁、有层次、更利于实现缓存等机制;

规范

协议

REST API与客户端通信协议为http协议;

域名

应该尽量将API放在专属于名下。

http://api.example.com

版本

应该将API的版本好放入URL中。

http://api.example.com/version/

路径

表示API的具体网址,在RESTful架构中,每个网址代表了一种资源,所以网址中不能有动词,只能有名词,故API中的名词应该用复数形式。

http动词

对http资源的具体操作类型,有http动词表示。

操作名称 请求动作名称
GET(SELET) 从服务器中获取资源
POST(CREATE) 在服务器中创建一个新的资源
PUT(UPDATE) 从服务器中更新资源
DELETE(DELETE) 从服务器中删除资源

过滤信息

过滤信息可以理解为query string即:?limit=10&page=1&id=12;为API提供参数,过滤并返回结果。

状态码

服务器向用户返回的状态吗和提示信息,常见的有以下部分:

  • 2XX:这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。
  • 3xx重定向:这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。当且仅当后续的请求所使用的方法是GET或者HEAD时,用户浏览器才可以在没有用户介入的情况下自动提交所需要的后续请求。客户端应当自动监测无限循环重定向(例如:A→B→C→……→A或A→A),因为这会导致服务器和客户端大量不必要的资源消耗。按照HTTP/1.0版规范的建议,浏览器不应自动访问超过5次的重定向。
  • 4xx客户端错误:这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。除非响应的是一个HEAD请求,否则服务器就应该返回一个解释当前错误状况的实体,以及这是临时的还是永久性的状况。这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误响应中的实体内容。
  • 5xx服务器错误:表示服务器无法完成明显有效的请求。这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。除非这是一个HEAD请求,否则服务器应当包含一个解释当前错误状态以及这个状况是临时的还是永久的解释信息实体。浏览器应当向用户展示任何在当前响应中被包含的实体。这些状态码适用于任何响应方法。
状态码 含义 备注
200 OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。 实际的响应将取决于所使用的请求方法。在GET请求中,响应将包含与请求的资源相对应的实体。在POST请求中,响应将包含描述或操作结果的实体。
201 Created 请求已经被实现,而且有一个新的资源已经依据请求的需要而创建,且其URI已经随Location头信息返回。 假如需要的资源无法及时创建的话,应当返回'202 Accepted'。
202 Accepted 服务器已接受请求,但尚未处理。最终该请求可能会也可能不会被执行,并且可能在处理发生时被禁止。
203 Non-Authoritative Information 服务器是一个转换代理服务器(transforming proxy,例如网络加速器),以200 OK状态码为起源,但回应了原始响应的修改版本。 自HTTP / 1.1起
204 No Content 服务器成功处理了请求,没有返回任何内容。
205 Reset Content 服务器成功处理了请求,但没有返回任何内容。 与204响应不同,此响应要求请求者重置文档视图。
206 Partial Content 服务器已经成功处理了部分GET请求。类似于FlashGet或者迅雷这类的HTTP。下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。
207 Multi-Status 代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。 (WebDAV;RFC 4918)
208 Already Reported DAV绑定的成员已经在(多状态)响应之前的部分被列举,且未被再次包含。
226 IM Used 服务器已经满足了对资源的请求,对实体请求的一个或多个实体操作的结果表示。
300 Multiple Choices 被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。 用户或浏览器能够自行选择一个首选的地址进行重定向。
301 Moved Permanently 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一。
302 Found 要求客户端执行临时重定向(原始描述短语为“Moved Temporarily”)。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。 只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
303 See Other 对应当前请求的响应可以在另一个URI上被找到,当响应于POST(或PUT / DELETE)接收到响应时,客户端应该假定服务器已经收到数据,并且应该使用单独的GET消息发出重定向。
304 Not Modified 表示资源未被修改,因为请求头指定的版本If-Modified-Since或If-None-Match。在这种情况下,由于客户端仍然具有以前下载的副本,因此不需要重新传输资源。
305 Use Proxy 被请求的资源必须通过指定的代理才能被访问。Location域中将给出指定的代理所在的URI信息,接收者需要重复发送一个单独的请求,通过这个代理才能访问相应资源。只有原始服务器才能创建305响应。许多HTTP客户端(像是Mozilla和Internet Explorer)都没有正确处理这种状态代码的响应,主要是出于安全考虑。
306 Switch Proxy 是指“后续请求应使用指定的代理”。 最新版的规范中,306状态码已经不再被使用。
307 Temporary Redirect 在这种情况下,请求应该与另一个URI重复,但后续的请求应仍使用原始的URI。 与302相反,当重新发出原始请求时,不允许更改请求方法。 例如,应该使用另一个POST请求来重复POST请求。
308 Permanent Redirect 请求和所有将来的请求应该使用另一个URI重复。 307和308重复302和301的行为,但不允许HTTP方法更改。 例如,将表单提交给永久重定向的资源可能会顺利进行。 .
400 Bad Request 由于明显的客户端错误(例如,格式错误的请求语法,太大的大小,无效的请求消息或欺骗性路由请求),服务器不能或不会处理该请求。
401 Unauthorized 类似于403 Forbidden,401语义即“未认证”,即用户没有必要的凭据。该状态码表示当前请求需要用户验证。该响应必须包含一个适用于被请求资源的WWW-Authenticate信息头用以询问用户信息。客户端可以重复提交一个包含恰当的Authorization头信息的请求。
402 Payment Required 该状态码是为了将来可能的需求而预留的。该状态码最初的意图可能被用作某种形式的数字现金或在线支付方案的一部分,但几乎没有哪家服务商使用,而且这个状态码通常不被使用。如果特定开发人员已超过请求的每日限制,Google Developers API会使用此状态码。
403 Forbidden 服务器已经理解请求,但是拒绝执行它。如果这不是一个HEAD请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个404响应,假如它不希望让客户端获得任何信息。 与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。
404 Not Found 请求失败,请求所希望得到的资源未被在服务器上发现,但允许用户的后续请求。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。
405 Method Not Allowed 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow头信息用以表示出当前资源能够接受的请求方法的列表。例如,需要通过POST呈现数据的表单上的GET请求,或只读资源上的PUT请求。
406 Not Acceptable 请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体,该请求不可接受。
407 Proxy Authentication Required 与401响应类似,只不过客户端必须在代理服务器上进行身份验证。
408 Request Timeout 请求超时。根据HTTP规范,客户端没有在服务器预备等待的时间内完成一个请求的发送,客户端可以随时再次提交这一请求而无需进行任何更改。
409 Conflict 表示因为请求存在冲突无法处理该请求,例如多个同步更新之间的编辑冲突。
410 Gone 表示所请求的资源不再可用,将不再可用。当资源被有意地删除并且资源应被清除时,应该使用这个。在收到410状态码后,用户应停止再次请求资源。但大多数服务端不会使用此状态码,而是直接使用404状态码。
500 Internal Server Error 通用错误消息,服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。没有给出具体错误信息。
501 Not Implemented 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
503 Service Unavailable 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是暂时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个Retry-After头用以标明这个延迟时间。如果没有给出这个Retry-After信息,那么客户端应当以处理500响应的方式处理它。
504 Gateway Timeout 作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。注意:某些代理服务器在DNS查询超时时会返回400或者500错误。

关于状态码详情参见“维基百科揭秘——HTTP状态码”;

错误信息

如果产生错误,就应该向用户返回出错信息。返回信息中将error作为建明,出错信息作为键值即可。

{
    "error":"Invalid API Key!"
}

返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

GET /collection: 返回资源对象列表
GET /collection/resource:返回单个资源对象
POST /collection:返回新创建的资源对象
PUT /collection:返回完整的资源对象
PATCh /collection:返回完整的资源对象
DELETE /collection:返回一个空文档

RESTful不规范使用

接口中添加GET/UPDATE等动词

在URI中添加操作名称;而是应该通过http动词表示请求资源的操作动作,如:GET/UPDATE,来表示接口的含义;

//不规范使用方法
GET /getUser
POST /updateUser
POST /cowfarm/cowfarmemp/new
POST /cowfarm/cowfarmemp/update
POST /cowfarm/cowfarmemp/delete/{id}

//正确使用方法
GET /user               # 获取一个用户的信息;
PUT /user               # 更新用户的信息;
POST /cowfarm/employee  # 表示 新建一个农场的雇员/员工;
PUT /cowfarm/employee   # 表示 更新农场雇员/员工的信息;
DELETE /cowfarm/employee# body中包含json参数,表示删除用户,且返回值中,message,code应该正常返回,data就没必要返回了

非改动资源的操作却设计为POST/PUT等方法

对于没有新增/更新/删除等去改动和影响资源的操作,HTTP的方法却设计为POST/PUT等

RESTful API返回数据的格式

常用数据返回格式为json格式,或者使用比较少的XML。


  1. 超文本:超文本系统是一种提供了复杂格式的解释的软件系统,包括文本,图像,超链接一种文字间的跳转以提供某一个关键词的相关内容。

  2. URI:统一资源标识符(英语:Uniform Resource Identifier,或URI)是一个用于标识某一互联网资源名称的字符串。可以这么理解URI=URL+URN;URL(定位符——资源地址)和URN(名称——资源名称)方案属于URI的子类,URI可以为URL或URN两者之一或同时是URI和URN。技术上讲,URL和URN属于资源ID;但是,人们往往无法将某种方案归类于两者中的某一个:所有的URI都可被作为名称看待,而某些方案同时体现了两者中的不同部分。

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

推荐阅读更多精彩内容