詳解REST架構(gòu)風(fēng)格

更新版本已經(jīng)發(fā)表在我的新博客峰髓。

REST

REST是Representational State Transfer(在表現(xiàn)層上的狀態(tài)轉(zhuǎn)化)的縮寫晚凿,這個(gè)詞的意思要在文章的后面才能解釋清楚梆暖。REST是一種WEB應(yīng)用的架構(gòu)風(fēng)格,它被定義為6個(gè)限制,滿足這6個(gè)限制响蕴,能夠獲得諸多優(yōu)點(diǎn)(詳細(xì)優(yōu)點(diǎn)在文章最后總結(jié))。

先用一句話來概括RESTful API(具有REST風(fēng)格的API): 用URL定位資源惠桃,用HTTP動(dòng)詞(GET,HEAD,POST,PUT,PATCH,DELETE)描述操作浦夷,用狀態(tài)碼表示操作結(jié)果。
但是REST遠(yuǎn)遠(yuǎn)不僅是指API的風(fēng)格辜王,它是一種WEB應(yīng)用的架構(gòu)風(fēng)格劈狐。我們到后面會(huì)有所體會(huì)。

引入:從另一個(gè)角度看待前后端

我們?yōu)g覽一個(gè)網(wǎng)站呐馆,說到底就是與這個(gè)網(wǎng)站中的資源進(jìn)行互動(dòng)(獲取肥缔、提交、修改汹来、刪除)辫继。前端的工作,就是為用戶從服務(wù)端獲取資源俗慈、展示資源姑宽、請(qǐng)求服務(wù)端改變資源。

RESTful API有助于客戶端和服務(wù)端的功能分離闺阱,服務(wù)器完全扮演著一個(gè)“資源服務(wù)商”的角色炮车。各種不同的客戶端都可以通過同一套API與這個(gè)“資源服務(wù)商”交流,從而與資源進(jìn)行互動(dòng)。


RESTful API

指定一個(gè)資源

在RESTful架構(gòu)風(fēng)格中瘦穆,URL用來指定一個(gè)資源纪隙。資源就是服務(wù)器上的數(shù)據(jù)。比如說URL/api/users表示的是該網(wǎng)站的所有用戶扛或,這是一種資源绵咱,可以與之互動(dòng)(獲取、提交熙兔、修改悲伶、刪除)。另外住涉,資源地址使用嵌套的結(jié)構(gòu)麸锉,比如/api/users/csr表示用戶名為'csr'的用戶,/api/users/csr/blogs表示'csr'的所有博客舆声,/api/users/csr/blogs/1234567表示其中的某一篇博客花沉。這些都是資源,后者嵌套在前者之中媳握。

既然URL表示一個(gè)資源碱屁,自然就不應(yīng)該包含動(dòng)詞,它應(yīng)該由名詞組成蛾找。一個(gè) not RESTful 的例子是通過向api/delete/resource發(fā)送GET請(qǐng)求來刪除一個(gè)資源娩脾。

更詳細(xì)的URL設(shè)計(jì)可以查看這篇博客。URL風(fēng)格只是REST的外表腋粥,不是本文的重點(diǎn)晦雨。

操作一個(gè)資源

既然通過URL能夠指定一個(gè)服務(wù)器上的資源。那么我們應(yīng)該如何與這個(gè)資源進(jìn)行互動(dòng)呢隘冲?我們對(duì)這個(gè)資源(URL)使用不同的HTTP方法闹瞧,就代表對(duì)這個(gè)資源的不同操作:

  • GET 獲取資源
  • HEAD 獲取資源的概況(響應(yīng)的HTTP只有head,沒有body)
  • POST 新建資源
  • PUT 更新資源(客戶端提供完整資源數(shù)據(jù))
  • PATCH 更新資源(客戶端提供需要修改的資源數(shù)據(jù))
  • DELETE 刪除資源

GET展辞、HEAD奥邮、PUT、DELETE方法是冪等方法(對(duì)于同一個(gè)內(nèi)容的請(qǐng)求罗珍,發(fā)出n次的效果與發(fā)出1次的效果相同)洽腺。
GET、HEAD方法是安全方法(不會(huì)造成服務(wù)器上資源的改變)覆旱。

PATCH不一定是冪等的蘸朋。PATCH的實(shí)現(xiàn)方式有可能是"提供一個(gè)用來替換的數(shù)據(jù)",也有可能是"提供一個(gè)更新數(shù)據(jù)的方法"(比如data++)扣唱。如果是后者藕坯,那么PATCH不是冪等的团南。

通過HTTP狀態(tài)碼來表示操作的結(jié)果

雖然HTTP狀態(tài)碼設(shè)計(jì)的本意就是表示操作結(jié)果,但是有時(shí)候人們往往沒有很好的利用它炼彪,RESTful API要求充分利用HTTP狀態(tài)碼

200 OK - [GET]:服務(wù)器成功返回用戶請(qǐng)求的數(shù)據(jù)吐根,該操作是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數(shù)據(jù)成功辐马。
202 Accepted - [*]:表示一個(gè)請(qǐng)求已經(jīng)進(jìn)入后臺(tái)排隊(duì)(異步任務(wù))
204 NO CONTENT - [DELETE]:用戶刪除數(shù)據(jù)成功拷橘。
400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發(fā)出的請(qǐng)求有錯(cuò)誤,服務(wù)器沒有進(jìn)行新建或修改數(shù)據(jù)的操作喜爷,該操作是冪等的冗疮。
401 Unauthorized - [*]:表示用戶沒有權(quán)限(令牌、用戶名贞奋、密碼錯(cuò)誤)赌厅。
403 Forbidden - [*] 表示用戶得到授權(quán)(與401錯(cuò)誤相對(duì))穷绵,但是訪問是被禁止的轿塔。
404 NOT FOUND - [*]:用戶發(fā)出的請(qǐng)求針對(duì)的是不存在的記錄,服務(wù)器沒有進(jìn)行操作仲墨,該操作是冪等的勾缭。
406 Not Acceptable - [GET]:用戶請(qǐng)求的格式不可得(比如用戶請(qǐng)求JSON格式,但是只有XML格式)目养。
410 Gone -[GET]:用戶請(qǐng)求的資源被永久刪除俩由,且不會(huì)再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí)癌蚁,發(fā)生一個(gè)驗(yàn)證錯(cuò)誤幻梯。
500 INTERNAL SERVER ERROR - [*]:服務(wù)器發(fā)生錯(cuò)誤,用戶將無法判斷發(fā)出的請(qǐng)求是否成功努释。

如何設(shè)計(jì)RESTful API

在過去不使用RESTful架構(gòu)風(fēng)格的時(shí)候碘梢,如果我們要設(shè)計(jì)一個(gè)系統(tǒng),會(huì)以“操作”為出發(fā)點(diǎn)伐蒂,然后圍繞它去建設(shè)其他需要的東西煞躬。
舉個(gè)例子,我們要向系統(tǒng)中增加一個(gè)用戶登陸的功能:

  1. 需要一個(gè)用戶登陸的功能(操作)
  2. 約定一個(gè)用于登錄的API(也就是URL)
  3. 約定這個(gè)API的使用方式(發(fā)送\響應(yīng)什么數(shù)據(jù)逸邦、格式是什么)
  4. 前后端針對(duì)這個(gè)API進(jìn)行開發(fā)

這種設(shè)計(jì)方式有如下缺點(diǎn):

  1. 當(dāng)我們不斷為這個(gè)系統(tǒng)增加操作恩沛,每增加一個(gè)操作都要按照上面的流程設(shè)計(jì)一次,第2和3點(diǎn)的工作實(shí)際是可以大大削減的(通過REST)缕减。
  2. 操作之間可能是有依賴的雷客,依賴多起來,系統(tǒng)會(huì)變得很復(fù)雜桥狡。
  3. 我們的API缺乏一致性(需要一份龐大的文檔來記錄api的地址搅裙、使用方式)妓局。
  4. 操作通常被認(rèn)為是有副作用(Side Effect)的,很難使用緩存技術(shù)呈宇。

而如果我們?cè)O(shè)計(jì)REST風(fēng)格的系統(tǒng)好爬,資源是第一位的考慮,首先從資源的角度進(jìn)行系統(tǒng)的拆分甥啄、設(shè)計(jì)存炮,而不是像以往一樣以操作為角度來進(jìn)行設(shè)計(jì)。

用兩個(gè)例子來說明:銀行的轉(zhuǎn)賬功能和matrix的提交功能蜈漓。

matrix是一個(gè)課程管理網(wǎng)站穆桂,可以提交作業(yè),讀者不知道也沒關(guān)系融虽。

這兩個(gè)功能非常具有“動(dòng)作性”享完,看起來和“資源”聯(lián)系不大,很容易就會(huì)設(shè)計(jì)成not RESTful的API:POST /transfer/${amount}/to/${toUserID}有额、POST api/assigments/${assigmentID}/submit般又。
一旦在URL中引入了動(dòng)詞,這個(gè)URL的功能就定死了巍佑,無法用于別的用途茴迁。而且各種功能的API各有各的結(jié)構(gòu),一致性很差萤衰,需要一份詳細(xì)的API文檔才能使用堕义。

這種情況下,要如何通過RESTful架構(gòu)風(fēng)格脆栋,設(shè)計(jì)一套一致倦卖、多用途的URL呢?
簡單地說椿争,就是將一個(gè)“動(dòng)作”理解為“操作一個(gè)資源”怕膛。這里的“操作”是指HTTP的方法。

對(duì)于轉(zhuǎn)賬動(dòng)作丘薛,就可以理解為“POST一個(gè)轉(zhuǎn)賬事務(wù)”嘉竟,因此API就可以設(shè)置成這樣: POST /transactions,請(qǐng)求體為:to=632&amount=500洋侨。這樣的設(shè)計(jì)不但簡潔明了舍扰,而且我們可以將這個(gè)URL用于別的用途:通過GET /transactions來獲取該用戶的所有轉(zhuǎn)賬事務(wù)。如果在這個(gè)URL的尾部加上transactionID我們還可以獲取某一次轉(zhuǎn)賬記錄希坚。

對(duì)于matrix的提交作業(yè)動(dòng)作边苹,我們可以理解為“POST一份作業(yè)答案”,所以API設(shè)計(jì)為POST /api/courses/${courseId}/assignments/${problemId}/submissions裁僧,在請(qǐng)求體中保存學(xué)生要提交的內(nèi)容个束。我們可以將這個(gè)URL用于別的用途:通過向這個(gè)URL發(fā)送GET請(qǐng)求來獲得該學(xué)生在這個(gè)題目的所有提交慕购。如果在這個(gè)URL的尾部加上submissionID我們還可以獲取、刪除茬底、更改某一個(gè)提交記錄沪悲。

從以上的兩個(gè)例子我們可以看出,使用RESTful風(fēng)格可以克服傳統(tǒng)架構(gòu)風(fēng)格的那4個(gè)缺陷:

  1. 設(shè)計(jì)API工作量減少阱表,因?yàn)楣δ苄枨笠坏┏鰜淼钊纾枰僮鞯馁Y源、操作的方式立刻就能分析出來最爬,因此資源URL和API的使用方式(GET, POST...)都很容易得到涉馁。
  2. 沒有了操作之間的依賴。資源之間雖然可能有關(guān)聯(lián)爱致,但是小得多烤送。
  3. 對(duì)資源的操作也就那么幾種(獲取、新建糠悯、修改帮坚、刪除),API的一致性逢防、自我描述性很強(qiáng)叶沛,不需要過多解釋蒲讯。
  4. 對(duì)于GET請(qǐng)求忘朝,我們都可以考慮使用緩存,因?yàn)樵赗ESTful的架構(gòu)中判帮,GET請(qǐng)求代表獲取數(shù)據(jù)局嘁,必須是安全、冪等的晦墙。

無狀態(tài)

根據(jù)REST的架構(gòu)限制悦昵,RESTful的服務(wù)器必須是無狀態(tài)的,這意味著來自客戶的每一個(gè)請(qǐng)求必須包含服務(wù)器處理該請(qǐng)求所需的所有信息晌畅, 服務(wù)器不能利用任何已經(jīng)存儲(chǔ)的“上下文(context但指,在這里表示用戶的狀態(tài))”來處理新到來的請(qǐng)求,會(huì)話狀態(tài)只能由客戶端來保存抗楔,并且在請(qǐng)求時(shí)一并提供棋凳。

這里注意兩點(diǎn)。1. 服務(wù)器不能存儲(chǔ)“上下文”不代表連數(shù)據(jù)庫都不能有连躏,“上下文”指那些在服務(wù)器內(nèi)存中的剩岳、非持久化的數(shù)據(jù)。2.
無狀態(tài)不代表不能有會(huì)話(sessions)入热,無狀態(tài)僅僅指服務(wù)器無狀態(tài)拍棕,會(huì)話的狀態(tài)由客戶端提供晓铆。

我一開始以為無狀態(tài)與用戶登陸是沖突的,后來在StackOverflow上找到了一個(gè)令我滿意的解答绰播。以下兩幅圖摘錄自這個(gè)答案骄噪。
無狀態(tài)的認(rèn)證機(jī)制:

無狀態(tài)的認(rèn)證機(jī)制

What you need is storing username and password on the client and send it with every request. You don't need more to do this than HTTP basic auth and an encrypted connection.
只需要將用戶名和密碼存儲(chǔ)在客戶端,然后客戶端每次發(fā)送請(qǐng)求都附帶上用戶名和密碼蠢箩。要做到這點(diǎn)你只需要HTTP基本認(rèn)證和一個(gè)加密的連接(HTTPS)腰池。
如果每次認(rèn)證,都要去數(shù)據(jù)庫查詢用戶的信息來核對(duì)忙芒,那么響應(yīng)會(huì)非常慢示弓,而且服務(wù)器也會(huì)有很大的性能損失。為了加快認(rèn)證的速度呵萨,最好在內(nèi)存中使用認(rèn)證緩存奏属。這并不違背“無狀態(tài)”的限制,因?yàn)榫彺娴淖饔脙H僅起加速的作用潮峦,沒有緩存照樣工作囱皿。

無狀態(tài)的第三方鑒權(quán)機(jī)制:


無狀態(tài)的第三方鑒權(quán)機(jī)制

What about 3rd party clients? They cannot have the username and password and all the permissions of the users. So you have to store separately what permissions a 3rd party client can have by a specific user. So the client developers can register they 3rd party clients, and get an unique API key and the users can allow 3rd party clients to access some part of their permissions. Like reading the name and email address, or listing their friends, etc... After allowing a 3rd party client the server will generate an access token. These access token can be used by the 3rd party client to access the permissions granted by the user.
通過這個(gè)方式,用戶可以給第三方應(yīng)用授權(quán)忱嘹,讓第三方應(yīng)用拿著用戶的“令牌”訪問網(wǎng)站的一些服務(wù)嘱腥。

以上兩幅圖講的是RESTful風(fēng)格的身份驗(yàn)證機(jī)制。在實(shí)踐中最好使用OAuth 2.0框架拘悦。

無狀態(tài)增強(qiáng)了系統(tǒng)的故障恢復(fù)能力齿兔,因?yàn)樵诜?wù)器上沒有保存session的狀態(tài),所以恢復(fù)起來更容易础米。
更重要的是分苇,無狀態(tài)意味著分布式系統(tǒng)能夠更好地工作,負(fù)載均衡器可以自由地將請(qǐng)求分發(fā)到任意的服務(wù)器屁桑。因?yàn)檎?qǐng)求中都已經(jīng)包含了服務(wù)器所需的所有信息医寿,任何服務(wù)器都可以處理。
并且蘑斧,無狀態(tài)讓系統(tǒng)的橫向拓展能力強(qiáng)大靖秩。因?yàn)椴恍枰诓煌姆?wù)器之間同步session狀態(tài),所以服務(wù)器之間的溝通開銷很低竖瘾。增加服務(wù)器的數(shù)量不會(huì)帶來明顯的性能損失(“1+1”更接近于“2”了)沟突。

HATEOAS

REST的4個(gè)層次

前面已經(jīng)討論了level 1和level 2,實(shí)際上REST還有一個(gè)更高的層次:HATEOAS(Hypermedia As The Engine Of Application State)准浴。

對(duì)于客戶端的資源請(qǐng)求事扭,服務(wù)器不僅要返回所請(qǐng)求的資源,而且要根據(jù)請(qǐng)求返回用戶所處的狀態(tài)和可轉(zhuǎn)移的狀態(tài)乐横。
客戶端不需要提前知道應(yīng)用有哪些狀態(tài)求橄,而是根據(jù)服務(wù)端響應(yīng)的“可轉(zhuǎn)移的狀態(tài)”今野,提供給用戶選擇,從而發(fā)生狀態(tài)轉(zhuǎn)移罐农。

這個(gè)例子這個(gè)例子都是不錯(cuò)的解釋条霜。

用簡單的話來說,在嚴(yán)格的RESTful架構(gòu)中涵亏,客戶端不需要提前知道服務(wù)端的API有哪些宰睡、怎么調(diào)用,在客戶端與服務(wù)器通信的過程中气筋,服務(wù)端會(huì)告訴客戶端:在你當(dāng)前所處的狀態(tài)下拆内,有哪些API可以使用、可以轉(zhuǎn)移到哪些狀態(tài)宠默。

既然服務(wù)器是無狀態(tài)的麸恍,那么它要如何知道發(fā)起請(qǐng)求的用戶處于什么狀態(tài)呢?這就要求客戶端在發(fā)送請(qǐng)求的時(shí)候要攜帶上足夠的信息搀矫,讓服務(wù)器能夠判斷客戶端的狀態(tài)抹沪。

這就很像10086的“電話自動(dòng)語音應(yīng)答服務(wù)”:你想要查詢你的手機(jī)流量,只需要會(huì)撥打“10086”瓤球,對(duì)方會(huì)提示你按下哪些按鍵就能進(jìn)入哪些狀態(tài)融欧。進(jìn)入下一個(gè)狀態(tài)以后,又會(huì)有語音提示你接下來能夠按哪些按鍵……最終卦羡,你能進(jìn)入到你想要的那個(gè)狀態(tài)(流量查詢服務(wù))噪馏。你需要記住的僅僅是“10086”這個(gè)號(hào)碼而已!

10086的語音提示相當(dāng)于Hypermedia虹茶,是驅(qū)動(dòng)應(yīng)用狀態(tài)轉(zhuǎn)換的“引擎”逝薪。

再進(jìn)一步想想,在RESTful架構(gòu)中蝴罪,所有的狀態(tài)其實(shí)就組成了一顆樹(更準(zhǔn)確地說是網(wǎng)):根節(jié)點(diǎn)就是網(wǎng)站的基地址。在你獲得一個(gè)節(jié)點(diǎn)中的資源的同時(shí)步清,服務(wù)器還會(huì)返回給你這個(gè)節(jié)點(diǎn)的邊:Hypermedia(超鏈接就是一種Hypermedia)要门。通過Hypermedia,你能夠知道如何跳轉(zhuǎn)到相鄰的節(jié)點(diǎn)廓啊。
結(jié)果就是:你能夠訪問到這顆樹的所有節(jié)點(diǎn)欢搜,而你所需要提前知道的只是“如何到達(dá)根節(jié)點(diǎn)”而已!

每個(gè)節(jié)點(diǎn)就是一個(gè)狀態(tài)谴轮〕次粒客戶端就在這個(gè)狀態(tài)網(wǎng)中不斷跳轉(zhuǎn)。

這種架構(gòu)的優(yōu)勢(shì)非常明顯:前后端之間的耦合更加微弱第步。
隨著應(yīng)用功能的升級(jí)改變疮装,“樹”的樣子會(huì)大大改變缘琅,但是只需要讓后端修改返回的資源內(nèi)容和Hypermedia,前端幾乎不用改動(dòng)廓推。功能的演化更加靈活了刷袍。

REST字面意思

現(xiàn)在你應(yīng)該明白R(shí)epresentational State Transfer中的State Transfer(狀態(tài)轉(zhuǎn)化)是什么意思了。那么Representational(表現(xiàn)層的)是什么意思呢樊展?
資源可以有很多種表示(representation)呻纹。表示是資源的外在形式,資源是表示的真正內(nèi)容专缠。不管用什么形式來表示雷酪,始終描述的是這個(gè)資源。當(dāng)我們討論“文章列表”這個(gè)資源時(shí)涝婉,我們并不在乎它是json格式還是xml格式太闺。但是當(dāng)我們真的要在服務(wù)器與客戶端之間傳輸數(shù)據(jù)的時(shí)候,不能說“傳輸資源”嘁圈,因?yàn)橘Y源太抽象了省骂,發(fā)送方必須要以某一種形式來傳遞它,接收方才能很好地解析最住。發(fā)送方與接收方之間傳輸?shù)木褪莚epresentation钞澳。
Roy Fielding的論文中有這個(gè)定義:A representation is a sequence of bytes, plus representation metadata to describe those bytes. HTTP報(bào)文是一種representation,header包含描述信息(尤其是Cnotent-Type這種)涨缚,body就是一個(gè)字節(jié)序列轧粟。除此之外,document, file也是representation脓魏。
Representational State Transfer的結(jié)構(gòu)是(Representational (State Transfer))兰吟,在這里我們用的是representation的形容詞形式,表示在表現(xiàn)的層次上討論狀態(tài)轉(zhuǎn)化茂翔。這個(gè)詞的字面意思是通過傳輸representation來觸發(fā)的客戶端狀態(tài)轉(zhuǎn)化混蔼。


總結(jié)

至此,我們應(yīng)該能夠體會(huì)到REST已經(jīng)不僅僅是一種API風(fēng)格了珊燎,它是一種軟件架構(gòu)風(fēng)格(REST本身不是一種架構(gòu))惭嚣。REST風(fēng)格的軟件架構(gòu)具有很強(qiáng)的演化、拓展能力:

  1. 一致的URL和HTTP動(dòng)詞使用:確保系統(tǒng)能夠接納多樣而又標(biāo)準(zhǔn)的客戶端悔政,保證客戶端的演化能力晚吞。
  2. 無狀態(tài):保證了系統(tǒng)的橫向拓展能力、服務(wù)端的演化能力谋国。
  3. HATEOAS:保證了應(yīng)用本身的演化能力(功能增加槽地、改變)。

這3點(diǎn)是單單對(duì)演化拓展優(yōu)勢(shì)的說明,這個(gè)回答總結(jié)了REST的6個(gè)約束分別對(duì)應(yīng)的優(yōu)點(diǎn)捌蚊。


參考資料

https://stackoverflow.com/questions/671118/what-exactly-is-restful-programming
https://stackoverflow.com/questions/6068113/do-sessions-really-violate-restfulness
https://martinfowler.com/articles/richardsonMaturityModel.html
https://www.zhihu.com/question/28557115
https://www.zhihu.com/question/33959971
RESTful API 設(shè)計(jì)指南
https://stackoverflow.com/a/10421579/8175856
https://en.wikipedia.org/wiki/Representational_state_transfer

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末集畅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逢勾,更是在濱河造成了極大的恐慌牡整,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溺拱,死亡現(xiàn)場離奇詭異逃贝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)迫摔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門沐扳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人句占,你說我怎么就攤上這事沪摄。” “怎么了纱烘?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵杨拐,是天一觀的道長。 經(jīng)常有香客問我擂啥,道長哄陶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任哺壶,我火速辦了婚禮屋吨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘山宾。我一直安慰自己至扰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布资锰。 她就那樣靜靜地躺著敢课,像睡著了一般。 火紅的嫁衣襯著肌膚如雪台妆。 梳的紋絲不亂的頭發(fā)上翎猛,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音接剩,去河邊找鬼。 笑死萨咳,一個(gè)胖子當(dāng)著我的面吹牛懊缺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼鹃两,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼遗座!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起俊扳,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤途蒋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后馋记,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體号坡,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年梯醒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宽堆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茸习,死狀恐怖畜隶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情号胚,我是刑警寧澤籽慢,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站猫胁,受9級(jí)特大地震影響箱亿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杜漠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一极景、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驾茴,春花似錦盼樟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至峡捡,卻和暖如春击碗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背们拙。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工稍途, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人砚婆。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓械拍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坷虑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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

  • 一說到REST甲馋,我想大家的第一反應(yīng)就是“啊,就是那種前后臺(tái)通信方式迄损《铮”但是在要求詳細(xì)講述它所提出的各個(gè)約束,以及如...
    時(shí)待吾閱讀 3,417評(píng)論 0 19
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理芹敌,服務(wù)發(fā)現(xiàn)痊远,斷路器,智...
    卡卡羅2017閱讀 134,637評(píng)論 18 139
  • 在工作中經(jīng)常有日常事務(wù)性工作党窜,人力資源管理的六大模塊就是其代表作拗引。作為HR對(duì)這幾大模塊都內(nèi)容與流程再清楚不過了。但...
    魔菇靜閱讀 281評(píng)論 4 4
  • 淡藍(lán)色的被子 我有一件淡藍(lán)色的毛衣 我就這樣躺著 做夢(mèng)或者無眠 灰色的天空 我有一條灰色的圍巾 我就這樣站著 發(fā)呆...
    差點(diǎn)成紳士閱讀 229評(píng)論 0 0