良好的 API 設(shè)計(jì)指南-RESTful API

要說RESTful首先來說說REST – REpresentational State Transfer (表述性狀態(tài)傳遞)

表述性狀態(tài)轉(zhuǎn)移是一組架構(gòu)約束條件和原則垫桂。滿足這些約束條件和原則的應(yīng)用程序或設(shè)計(jì)就是RESTful幌陕。需要注意的是盾鳞,REST是設(shè)計(jì)風(fēng)格而不是標(biāo)準(zhǔn)安皱。

以上的概念大概是許多關(guān)于RESTful中都會出現(xiàn)的定義概念刷袍。

那么什么是表述性狀態(tài)轉(zhuǎn)移呢米碰?

首先谷丸,之所以晦澀是因?yàn)榍懊嬷髡Z被去掉了堡掏,全稱是 Resource Representational State Transfer,通俗來講就是刨疼,資源在網(wǎng)絡(luò)中以某種表現(xiàn)形式進(jìn)行狀態(tài)轉(zhuǎn)移布疼。

在查詢很多資料后看到一句很精簡的總結(jié):

URL定位資源,用HTTP動詞(GET,POST,DELETE,PUT等)描述操作币狠。

既然說到了是用HTTP動詞進(jìn)行操作游两。那么需要了解這里列出的4.5個(gè)非常重要的HTTP動作,這里的0.5個(gè)是指PATCH漩绵,因?yàn)樗诠δ苌吓cPUT非常類似贱案,剩下4個(gè)通常被API開發(fā)人員兩兩結(jié)合使用

  • GET(SELECT):從服務(wù)器獲取一個(gè)指定資源或一個(gè)資源集合;
  • POST(CREATE):在服務(wù)器上創(chuàng)建一個(gè)資源止吐;
  • PUT(UPDATE):更新服務(wù)器上的一個(gè)資源宝踪,需要提供整個(gè)資源;
  • PATCH(UPDATE):更新服務(wù)器上的一個(gè)資源碍扔,只提供資源中改變的那部分屬性瘩燥;
  • DELETE(DELETE):移除服務(wù)器上的一個(gè)資源;

還有兩個(gè)不常見的HTTP動作:

  • HEAD – 獲取一個(gè)資源的元數(shù)據(jù)不同,例如一組hash數(shù)據(jù)或者資源的最近一次更新時(shí)間厉膀;
  • OPTIONS – 獲取當(dāng)前用戶(Consumer)對資源的訪問權(quán)限;

關(guān)于RESTful的API設(shè)計(jì)風(fēng)格二拐,說完RESTful接下來該說說API了服鹅。

API是服務(wù)提供方和使用方之間的契約,打破該契約將會給服務(wù)端開發(fā)人員招來非常大的麻煩百新,這些麻煩來自于使用API的開發(fā)人員企软,因?yàn)閷PI的改動會導(dǎo)致他們的移動app無法工作。一個(gè)好的文檔對于解決這些事情能起到事半功倍的作用饭望,但是絕對多數(shù)程序員都不喜歡寫文檔仗哨。如果想讓服務(wù)端的價(jià)值更好的體現(xiàn)出來,就要好好設(shè)計(jì)API铅辞。通過這些API厌漂,你的服務(wù)/核心程序?qū)⒂锌赡艹蔀槠渌?xiàng)目所依賴的平臺;你提供的API越易用巷挥,就會有越多人愿意使用它桩卵。規(guī)劃API的展示形式可能比你想象的要簡單,首先要確定你的數(shù)據(jù)是如何設(shè)計(jì)以及核心程序是如何工作的。

image.png

也就是說Server提供的RESTful API中雏节,URL中只使用名詞來指定資源胜嗓,原則上不使用動詞」痴В“資源”是REST架構(gòu)或者說整個(gè)網(wǎng)絡(luò)處理的核心辞州。

那么下面來具體說說如何形成良好的RESTful風(fēng)格的API設(shè)計(jì)

1. 使用名詞而不是動詞
Server提供的RESTful API中,URL中只使用名詞來指定資源寥粹,原則上不使用動詞变过。“資源”是REST架構(gòu)或者說整個(gè)網(wǎng)絡(luò)處理的核心涝涤。比如:

2.Get方法和查詢參數(shù)不應(yīng)該涉及狀態(tài)改變
使用PUT, POST 和DELETE 方法 而不是 GET 方法來改變狀態(tài)糊肠,不要使用GET 進(jìn)行狀態(tài)改變:
通常辨宠,GET請求能夠被瀏覽器緩存(而且通常都會這么做),例如货裹,當(dāng)用戶發(fā)起第二次POST請求時(shí)嗤形,緩存的GET請求(依賴于緩存首部)能夠加快用戶的訪問速度。一個(gè)HEAD請求基本上就是一個(gè)沒有返回體的GET請求弧圆,因此也能被緩存赋兵。

3.使用復(fù)數(shù)名詞
不要混淆名詞單數(shù)和復(fù)數(shù),為了保持簡單墓阀,只對所有資源使用復(fù)數(shù)毡惜。

4. 使用子資源表達(dá)關(guān)系
如果一個(gè)資源與另外一個(gè)資源有關(guān)系,使用子資源:

5.使用Http頭聲明序列化格式
在客戶端和服務(wù)端斯撮,雙方都要知道通訊的格式,格式在HTTP-Header中指定
Content-Type 定義請求格式
Accept 定義系列可接受的響應(yīng)格式

6.使用HATEOAS
Hypermedia as the Engine of Application State 超媒體作為應(yīng)用狀態(tài)的引擎扶叉,超文本鏈接可以建立更好的文本瀏覽:

7.為集合提供過濾 排序 選擇和分頁等功能
Filtering過濾:

使用唯一的查詢參數(shù)進(jìn)行過濾:

GET /cars?color=red 返回紅色的cars
GET /cars?seats<=2 返回小于兩座位的cars集合

當(dāng)用戶請求獲取一組對象列表時(shí)勿锅,你就需要對結(jié)果進(jìn)行過濾并返回一組嚴(yán)格符合用戶要求的對象。有時(shí)返回結(jié)果的數(shù)量可能非常大枣氧,但是你也不能隨意對此進(jìn)行約束溢十,因?yàn)檫@種服務(wù)端的隨意約束會造成第三方開發(fā)人員的困惑。如果用戶請求了一個(gè)集合达吞,并對返回結(jié)果進(jìn)行遍歷张弛,然后只要前100個(gè)對象,那么這里就需要由用戶來指明這個(gè)限制量。這樣用戶就不會有這樣的疑惑:是他們程序的bug還是接口限制了100條吞鸭?還是網(wǎng)絡(luò)只允許傳這么大的包寺董?

Sorting排序:

允許針對多個(gè)字段排序

GET /cars?sort=-manufactorer,+model

這是返回根據(jù)生產(chǎn)者降序和模型升序排列的car集合

Field selection

移動端能夠顯示其中一些字段,它們其實(shí)不需要一個(gè)資源的所有字段刻剥,給API消費(fèi)者一個(gè)選擇字段的能力遮咖,這會降低網(wǎng)絡(luò)流量,提高API可用性造虏。

GET /cars?fields=manufacturer,model,id,color

Paging分頁

使用 limit 和offset.實(shí)現(xiàn)分頁御吞,缺省limit=20 和offset=0;

GET /cars?offset=10&limit=5

為了將總數(shù)發(fā)給客戶端漓藕,使用訂制的HTTP頭: X-Total-Count.

鏈接到下一頁或上一頁可以在HTTP頭的link規(guī)定陶珠,遵循Link規(guī)定:

Link:
https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5; rel=”next”,
https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3; rel=”last”,
https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5; rel=”first”,
https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5; rel=”prev”,

8.版本化你的API
也就是進(jìn)行版本控制。無論你在設(shè)計(jì)什么系統(tǒng)享钞,也不管你事先做了多么詳盡的計(jì)劃背率,隨著時(shí)間的推移和業(yè)務(wù)的發(fā)展,你的程序總會發(fā)生變化嫩与,數(shù)據(jù)關(guān)系也會發(fā)生變化寝姿,資源可能會被添加或者刪除一些屬性。只要軟件還在生存期內(nèi)并且還有人在用它划滋,開發(fā)人員就得面對這些問題饵筑,對于API設(shè)計(jì)來說,尤其如此处坪。

在URL中加入版本號是一個(gè)優(yōu)秀的API設(shè)計(jì)根资,當(dāng)然還有另一個(gè)常用的解決辦法就是把版本號放在請求首部中

使得API版本變得強(qiáng)制性,不要發(fā)布無版本的API同窘,使用簡單數(shù)字玄帕,避免小數(shù)點(diǎn)如2.5。一般在Url后面使用?v

/blog/api/v1

9. 使用Http狀態(tài)碼處理錯(cuò)誤
如果你的API沒有錯(cuò)誤處理是很難的想邦,只是返回500和出錯(cuò)堆棧不一定有用

Http狀態(tài)碼提供70個(gè)出錯(cuò)裤纹,我們只要使用10個(gè)左右:

200 – OK – 一切正常
201 – OK – 新的資源已經(jīng)成功創(chuàng)建
204 – OK – 資源已經(jīng)成功擅長

304 – Not Modified – 客戶端使用緩存數(shù)據(jù)

400 – Bad Request – 請求無效,需要附加細(xì)節(jié)解釋如 “JSON無效”
401 – Unauthorized – 請求需要用戶驗(yàn)證
403 – Forbidden – 服務(wù)器已經(jīng)理解了請求丧没,但是拒絕服務(wù)或這種請求的訪問是不允許的鹰椒。
404 – Not found – 沒有發(fā)現(xiàn)該資源
422 – Unprocessable Entity – 只有服務(wù)器不能處理實(shí)體時(shí)使用,比如圖像不能被格式化呕童,或者重要字段丟失漆际。

500 – Internal Server Error – API開發(fā)者應(yīng)該避免這種錯(cuò)誤。

1XX的返回碼預(yù)留給HTTP的底層使用夺饲,在你的整個(gè)職業(yè)生涯中都不會主動發(fā)送這種返回碼奸汇;

2XX的返回碼表示請求按照預(yù)期執(zhí)行并成功返回了信息施符。服務(wù)端要盡可能給用戶返回這種結(jié)果。

3XX的返回碼表示請求重定向擂找,大多數(shù)API都不會經(jīng)常使用這種請求()戳吝,但是最新的超媒體API會充分使用這些功能。

4XX的返回碼主要表示由客戶端引起的錯(cuò)誤婴洼,例如請求參數(shù)錯(cuò)誤或者訪問一個(gè)不存在的資源骨坑,這些必須為冪等操作,并且不能改變服務(wù)器的狀態(tài)(其實(shí)服務(wù)器的狀態(tài)發(fā)生了改變就意味著操作不是冪等了)柬采。

5XX的返回碼主要表示由服務(wù)器引起的錯(cuò)誤欢唾,通常情況下,這些錯(cuò)誤都是開發(fā)人員

使用詳細(xì)的錯(cuò)誤包裝錯(cuò)誤:

{

  "errors": [

   {

    "userMessage": "Sorry, the requested resource does not exist",

    "internalMessage": "No car found in the database",

    "code": 34,

    "more info": "http://dev.mwaysolutions.com/blog/api/v1/errors/12345"

   }

  ]

}12345678910111213141516171819

10.允許覆蓋http方法
一些代理只支持POST 和 GET方法粉捻, 為了使用這些有限方法支持RESTful API礁遣,需要一種辦法覆蓋http原來的方法。

使用訂制的HTTP頭 X-HTTP-Method-Override 來覆蓋POST 方法.

使用場景

版本號

在 RESTful API 中肩刃,API 接口應(yīng)該盡量兼容之前的版本祟霍。但是,在實(shí)際業(yè)務(wù)開發(fā)場景中盈包,可能隨著業(yè)務(wù)需求的不斷迭代沸呐,現(xiàn)有的 API 接口無法支持舊版本的適配,此時(shí)如果強(qiáng)制升級服務(wù)端的 API 接口將導(dǎo)致客戶端舊有功能出現(xiàn)故障呢燥。實(shí)際上崭添,Web 端是部署在服務(wù)器,因此它可以很容易為了適配服務(wù)端的新的 API 接口進(jìn)行版本升級叛氨,然而像 Android 端、IOS 端仁连、PC 端等其他客戶端是運(yùn)行在用戶的機(jī)器上怖糊,因此當(dāng)前產(chǎn)品很難做到適配新的服務(wù)端的 API 接口遣钳,從而出現(xiàn)功能故障姐直,這種情況下姻成,用戶必須升級產(chǎn)品到最新的版本才能正常使用。

為了解決這個(gè)版本不兼容問題,在設(shè)計(jì) RESTful API 的一種實(shí)用的做法是使用版本號。一般情況下哨查,我們會在 url 中保留版本號浙于,并同時(shí)兼容多個(gè)版本。

【GET】  /v1/users/{user_id}  // 版本 v1 的查詢用戶列表的 API 接口
【GET】  /v2/users/{user_id}  // 版本 v2 的查詢用戶列表的 API 接口

現(xiàn)在,我們可以不改變版本 v1 的查詢用戶列表的 API 接口的情況下,新增版本 v2 的查詢用戶列表的 API 接口以滿足新的業(yè)務(wù)需求吆玖,此時(shí)翅阵,客戶端的產(chǎn)品的新功能將請求新的服務(wù)端的 API 接口地址漱贱。雖然服務(wù)端會同時(shí)兼容多個(gè)版本崇摄,但是同時(shí)維護(hù)太多版本對于服務(wù)端而言是個(gè)不小的負(fù)擔(dān)厕氨,因?yàn)榉?wù)端要維護(hù)多套代碼国葬。這種情況下,常見的做法不是維護(hù)所有的兼容版本汇四,而是只維護(hù)最新的幾個(gè)兼容版本接奈,例如維護(hù)最新的三個(gè)兼容版本序宦。在一段時(shí)間后糠惫,當(dāng)絕大多數(shù)用戶升級到較新的版本后备燃,廢棄一些使用量較少的服務(wù)端的老版本API 接口版本并齐,并要求使用產(chǎn)品的非常舊的版本的用戶強(qiáng)制升級漏麦。

注意的是,“不改變版本 v1 的查詢用戶列表的 API 接口”主要指的是對于客戶端的調(diào)用者而言它看起來是沒有改變测垛。而實(shí)際上捏膨,如果業(yè)務(wù)變化太大,服務(wù)端的開發(fā)人員需要對舊版本的 API 接口使用適配器模式將請求適配到新的API 接口上食侮。

資源路徑

RESTful API 的設(shè)計(jì)以資源為核心号涯,每一個(gè) URI 代表一種資源。因此锯七,URI 不能包含動詞链快,只能是名詞。注意的是起胰,形容詞也是可以使用的久又,但是盡量少用。一般來說效五,不論資源是單個(gè)還是多個(gè)地消,API 的名詞要以復(fù)數(shù)進(jìn)行命名。此外畏妖,命名名詞的時(shí)候脉执,要使用小寫、數(shù)字及下劃線來區(qū)分多個(gè)單詞戒劫。這樣的設(shè)計(jì)是為了與 json 對象及屬性的命名方案保持一致半夷。例如婆廊,一個(gè)查詢系統(tǒng)標(biāo)簽的接口可以進(jìn)行如下設(shè)計(jì)。

【GET】  /v1/tags/{tag_id} 

同時(shí)巫橄,資源的路徑應(yīng)該從根到子依次如下淘邻。

/{resources}/{resource_id}/{sub_resources}/{sub_resource_id}/{sub_resource_property}

我們來看一個(gè)“添加用戶的角色”的設(shè)計(jì)奔坟,其中“用戶”是主資源读整,“角色”是子資源。

【POST】  /v1/users/{user_id}/roles/{role_id} // 添加用戶的角色

有的時(shí)候炊林,當(dāng)一個(gè)資源變化難以使用標(biāo)準(zhǔn)的 RESTful API 來命名彩倚,可以考慮使用一些特殊的 actions 命名筹我。

/{resources}/{resource_id}/actions/{action}

舉個(gè)例子,“密碼修改”這個(gè)接口的命名很難完全使用名詞來構(gòu)建路徑帆离,此時(shí)可以引入 action 命名蔬蕊。

【PUT】  /v1/users/{user_id}/password/actions/modify // 密碼修改

請求方式

可以通過 GET、 POST哥谷、 PUT岸夯、 PATCH、 DELETE 等方式對服務(wù)端的資源進(jìn)行操作呼巷。其中囱修,GET 用于查詢資源,POST 用于創(chuàng)建資源王悍,PUT 用于更新服務(wù)端的資源的全部信息破镰,PATCH 用于更新服務(wù)端的資源的部分信息,DELETE 用于刪除服務(wù)端的資源压储。

這里鲜漩,筆者使用“用戶”的案例進(jìn)行回顧通過 GET、 POST集惋、 PUT孕似、 PATCH、 DELETE 等方式對服務(wù)端的資源進(jìn)行操作刮刑。

【GET】          /users                # 查詢用戶信息列表
【GET】          /users/1001           # 查看某個(gè)用戶信息
【POST】         /users                # 新建用戶信息
【PUT】          /users/1001           # 更新用戶信息(全部字段)
【PATCH】        /users/1001           # 更新用戶信息(部分字段)
【DELETE】       /users/1001           # 刪除用戶信息

查詢參數(shù)

RESTful API 接口應(yīng)該提供參數(shù)喉祭,過濾返回結(jié)果。其中雷绢,offset 指定返回記錄的開始位置泛烙。一般情況下,它會結(jié)合 limit 來做分頁的查詢翘紊,這里 limit 指定返回記錄的數(shù)量蔽氨。

【GET】  /{version}/{resources}/{resource_id}?offset=0&limit=20

同時(shí),orderby 可以用來排序,但僅支持單個(gè)字符的排序鹉究,如果存在多個(gè)字段排序宇立,需要業(yè)務(wù)中擴(kuò)展其他參數(shù)進(jìn)行支持。

【GET】  /{version}/{resources}/{resource_id}?orderby={field} [asc|desc]

為了更好地選擇是否支持查詢總數(shù)自赔,我們可以使用 count 字段妈嘹,count 表示返回?cái)?shù)據(jù)是否包含總條數(shù),它的默認(rèn)值為 false匿级。

【GET】  /{version}/{resources}/{resource_id}?count=[true|false]

上面介紹的 offset蟋滴、 limit、 orderby 是一些公共參數(shù)痘绎。此外,業(yè)務(wù)場景中還存在許多個(gè)性化的參數(shù)肖粮。我們來看一個(gè)例子孤页。

【GET】  /v1/categorys/{category_id}/apps/{app_id}?enable=[1|0]&os_type={field}&device_ids={field,field,…}

注意的是,不要過度設(shè)計(jì)涩馆,只返回用戶需要的查詢參數(shù)行施。此外,需要考慮是否對查詢參數(shù)創(chuàng)建數(shù)據(jù)庫索引以提高查詢性能魂那。

狀態(tài)碼

使用適合的狀態(tài)碼很重要蛾号,而不應(yīng)該全部都返回狀態(tài)碼 200,或者隨便亂使用涯雅。這里鲜结,列舉筆者在實(shí)際開發(fā)過程中常用的一些狀態(tài)碼,以供參考活逆。

狀態(tài)碼 描述
200 請求成功
201 創(chuàng)建成功
400 錯(cuò)誤的請求
401 未驗(yàn)證
403 被拒絕
404 無法找到
409 資源沖突
500 服務(wù)器內(nèi)部錯(cuò)誤

異常響應(yīng)

當(dāng) RESTful API 接口出現(xiàn)非 2xx 的 HTTP 錯(cuò)誤碼響應(yīng)時(shí)精刷,采用全局的異常結(jié)構(gòu)響應(yīng)信息。

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
    "code": "INVALID_ARGUMENT",
    "message": "{error message}",
    "cause": "{cause message}",
    "request_id": "01234567-89ab-cdef-0123-456789abcdef",
    "host_id": "{server identity}",
    "server_time": "2014-01-01T12:00:00Z"
}

請求參數(shù)

在設(shè)計(jì)服務(wù)端的 RESTful API 的時(shí)候蔗候,我們還需要對請求參數(shù)進(jìn)行限制說明怒允。例如一個(gè)支持批量查詢的接口,我們要考慮最大支持查詢的數(shù)量锈遥。

【GET】     /v1/users/batch?user_ids=1001,1002      // 批量查詢用戶信息
參數(shù)說明
- user_ids: 用戶ID串纫事,最多允許 20 個(gè)。

此外所灸,在設(shè)計(jì)新增或修改接口時(shí)丽惶,我們還需要在文檔中明確告訴調(diào)用者哪些參數(shù)是必填項(xiàng),哪些是選填項(xiàng)庆寺,以及它們的邊界值的限制蚊夫。

【POST】     /v1/users                             // 創(chuàng)建用戶信息
請求內(nèi)容
{
    "username": "lgz",                 // 必填, 用戶名稱, max 10
    "realname": "梁桂釗",               // 必填, 用戶名稱, max 10
    "password": "123456",              // 必填, 用戶密碼, max 32
    "email": "lianggzone@163.com",     // 選填, 電子郵箱, max 32
    "weixin": "LiangGzone",            // 選填,微信賬號, max 32
    "sex": 1                           // 必填, 用戶性別[1-男 2-女 99-未知]
}

響應(yīng)參數(shù)

針對不同操作懦尝,服務(wù)端向用戶返回的結(jié)果應(yīng)該符合以下規(guī)范知纷。

【GET】     /{version}/{resources}/{resource_id}      // 返回單個(gè)資源對象
【GET】     /{version}/{resources}                    // 返回資源對象的列表
【POST】    /{version}/{resources}                    // 返回新生成的資源對象
【PUT】     /{version}/{resources}/{resource_id}      // 返回完整的資源對象
【PATCH】   /{version}/{resources}/{resource_id}      // 返回完整的資源對象
【DELETE】  /{version}/{resources}/{resource_id}      // 狀態(tài)碼 200壤圃,返回完整的資源對象。
                                                      // 狀態(tài)碼 204琅轧,返回一個(gè)空文檔

如果是單條數(shù)據(jù)伍绳,則返回一個(gè)對象的 JSON 字符串。

HTTP/1.1 200 OK
{
    "id" : "01234567-89ab-cdef-0123-456789abcdef",
    "name" : "example",
    "created_time": 1496676420000,
    "updated_time": 1496676420000,
    ...
}

如果是列表數(shù)據(jù)乍桂,則返回一個(gè)封裝的結(jié)構(gòu)體冲杀。

HTTP/1.1 200 OK
{
    "count":100,
    "items":[
        {
            "id" : "01234567-89ab-cdef-0123-456789abcdef",
            "name" : "example",
            "created_time": 1496676420000,
            "updated_time": 1496676420000,
            ...
        },
        ...
    ]
}

一個(gè)完整的案例

最后,我們使用一個(gè)完整的案例將前面介紹的知識整合起來睹酌。這里权谁,使用“獲取用戶列表”的案例。

【GET】     /v1/users?[&keyword=xxx][&enable=1][&offset=0][&limit=20] 獲取用戶列表
功能說明:獲取用戶列表
請求方式:GET
參數(shù)說明
- keyword: 模糊查找的關(guān)鍵字憋沿。[選填]
- enable: 啟用狀態(tài)[1-啟用 2-禁用]旺芽。[選填]
- offset: 獲取位置偏移,從 0 開始辐啄。[選填]
- limit: 每次獲取返回的條數(shù)采章,缺省為 20 條,最大不超過 100壶辜。 [選填]
響應(yīng)內(nèi)容
HTTP/1.1 200 OK
{
    "count":100,
    "items":[
        {
            "id" : "01234567-89ab-cdef-0123-456789abcdef",
            "name" : "example",
            "created_time": 1496676420000,
            "updated_time": 1496676420000,
            ...
        },
        ...
    ]
}
失敗響應(yīng)
HTTP/1.1 403 UC/AUTH_DENIED
Content-Type: application/json
{
    "code": "INVALID_ARGUMENT",
    "message": "{error message}",
    "cause": "{cause message}",
    "request_id": "01234567-89ab-cdef-0123-456789abcdef",
    "host_id": "{server identity}",
    "server_time": "2014-01-01T12:00:00Z"
}
錯(cuò)誤代碼
- 403 UC/AUTH_DENIED    授權(quán)受限
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悯舟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子砸民,更是在濱河造成了極大的恐慌抵怎,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阱洪,死亡現(xiàn)場離奇詭異便贵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)冗荸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門承璃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蚌本,你說我怎么就攤上這事盔粹。” “怎么了程癌?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵舷嗡,是天一觀的道長。 經(jīng)常有香客問我嵌莉,道長进萄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮中鼠,結(jié)果婚禮上可婶,老公的妹妹穿的比我還像新娘。我一直安慰自己援雇,他們只是感情好矛渴,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惫搏,像睡著了一般具温。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上筐赔,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天铣猩,我揣著相機(jī)與錄音,去河邊找鬼川陆。 笑死剂习,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的较沪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼失仁,長吁一口氣:“原來是場噩夢啊……” “哼尸曼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起萄焦,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤控轿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拂封,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茬射,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年冒签,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了在抛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡萧恕,死狀恐怖刚梭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情票唆,我是刑警寧澤朴读,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站走趋,受9級特大地震影響衅金,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一氮唯、第九天 我趴在偏房一處隱蔽的房頂上張望鉴吹。 院中可真熱鬧,春花似錦您觉、人聲如沸拙寡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肆糕。三九已至,卻和暖如春在孝,著一層夾襖步出監(jiān)牢的瞬間诚啃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工私沮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留始赎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓仔燕,卻偏偏與公主長得像造垛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子晰搀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359

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