Hyperledger fabric grpc 源碼分析--- error:connection failed

(目前有點(diǎn)亂疤估,先貼上來(lái),等以后有時(shí)間在整理吧俺叭。這個(gè)問(wèn)題一直想拿出來(lái)分享,還有兩個(gè)博客泰偿,都是相關(guān)的绪颖,一點(diǎn)點(diǎn)發(fā)出來(lái))

最近要在fabric網(wǎng)絡(luò)和外部添加一層load balance,然后使用node的grpcs調(diào)用nginx甜奄,再轉(zhuǎn)發(fā)到peer或者orderer。但是一直顯示code 14 connect failed窃款。log信息少的可憐课兄。所以索性就過(guò)一遍代碼。找找區(qū)別晨继,順便打打log烟阐。

版本

fabric-client和grpc的版本

$ npm ls | grep fabric
+-- fabric-ca-client@1.0.8
+-- fabric-client@1.0.8

$ npm ls | grep grpc
`-- grpc@1.10.1

fabric版本:

這里面要注意,fabric-node-sdk這個(gè)版本強(qiáng)制要求grpc的版本要高于1.10.1。

fabric sdk node的grpc

然后我們就開始跟蹤fabric進(jìn)行一個(gè)request的全過(guò)程蜒茄。
我們跟蹤的方法時(shí)client.installChaincode()唉擂。

  1. 構(gòu)建proposal
    其內(nèi)部針對(duì)request和chaincode的相關(guān)數(shù)據(jù)進(jìn)行了封裝,然后用userContext的secure進(jìn)行簽名檀葛。最后調(diào)用clientUtils.sendPeersProposal(peers, signed_proposal, timeout)玩祟。
  2. 遍歷peers的list,然后調(diào)用peer.sendProposal(proposal, timeout)屿聋。
  3. peer的構(gòu)建和發(fā)起請(qǐng)求

SDK中Peer是繼承了Remote類空扎。

Remote類主要就是兩件事情:

  • 構(gòu)造器針對(duì)grpc的各個(gè)參數(shù)進(jìn)行配置,主要包括
    • ssl-target-name-override:如果server是tls開啟的狀態(tài)润讥,而且hostname的名字和tls證書的CN域名不同转锈,那么就可以在這里指定CN的那個(gè)hostname。而且楚殿,這個(gè)選項(xiàng)更改了grpc的兩個(gè)屬性:
      • grpc.ssl_target_name_override
      • grpc.default_authority這個(gè)參數(shù)就是針對(duì)server的證書進(jìn)行驗(yàn)證撮慨。如果hostname和證書的簽名是一致的,則這個(gè)參數(shù)并不需要脆粥。
    • pemserver的tls證書內(nèi)容砌溺。
    • 還有一些其他的grpc設(shè)置
      • grpc.max_receive_message_length
      • grpc.max_send_message_length
    • request-timeout配置一個(gè)grpc的request超時(shí)時(shí)間
  • 構(gòu)建內(nèi)置類-Endpoint
    • 這個(gè)類非常重要,它是構(gòu)建grpc對(duì)象的核心冠绢。主要就是針對(duì)url判斷protocol抚吠,如果是grpcs則會(huì)使用this.creds = grpc.credentials.createSsl(pembuf)構(gòu)建一個(gè)ssl的通道;如果是grpc則使用grpc.credentials.createInsecure()構(gòu)建通道弟胀。

Peer發(fā)起的請(qǐng)求sendProposal楷力,直接調(diào)用grpc的方法等待response:self._endorserClient.processProposal(proposal, function(err, proposalResponse){}
這里要注意的是孵户,其調(diào)用的grpc的simple RPC方法萧朝,發(fā)送一個(gè)請(qǐng)求,并且等待請(qǐng)求的response夏哭。不是array也不是stream的形式检柬。
查看了下grpc的service的定義,果然竖配,直接發(fā)送object:

service Endorser {
    rpc ProcessProposal(SignedProposal) returns (ProposalResponse) {}
}
  1. node Grpc調(diào)用

src中核心組件就是client.jscredentials.js何址。前者負(fù)責(zé)請(qǐng)求調(diào)用,后者負(fù)責(zé)channel的創(chuàng)建接口(前面提到的兩個(gè)創(chuàng)建通道的方法定義于此)进胯。我們重點(diǎn)看client.js用爪。我們逐個(gè)函數(shù)(精力有限,先分析用到的)的分析:
(有一些需要后續(xù)補(bǔ)充的胁镐,EventEmitter-event調(diào)用偎血,stream-流)
* createStatusError:如果grpc返回的數(shù)據(jù)有error诸衔,則通過(guò)該函數(shù)解析,返回error
* ClientUnaryCall綁定一個(gè)event-EventEmitter颇玷。
* _readsDone當(dāng)server發(fā)送消息完成之后笨农,client會(huì)調(diào)用方法,并確認(rèn)狀態(tài)帖渠。默認(rèn)為ok
* _receiveStatus當(dāng)從server收到任何status信息時(shí)候谒亦,調(diào)用。
* Client(address, credentials, options)構(gòu)造函數(shù)阿弃,創(chuàng)建一個(gè)channel诊霹。在創(chuàng)建一個(gè)grpc的client的時(shí)候就調(diào)用了。
* makeClientConstructor在后面有一個(gè)導(dǎo)出函數(shù)渣淳,來(lái)具體根據(jù)需求創(chuàng)建不同類型的Client脾还,其中request的類型
* Client.prototype.makeUnaryRequest普通Grpc調(diào)用,創(chuàng)建請(qǐng)求入愧”陕可以給出序列化和反序列化的方法,以及一些參數(shù)和回調(diào)函數(shù)棺蛛。
* getCall(channel, method, options):這里面有些參數(shù)設(shè)置怔蚌,然后將一個(gè)call返回-new grpc.Call(channel, method, deadline, host,parent, propagate_flags);
* hostname:server ip
* deadline:這個(gè)connection的timeout
* credential:如果這個(gè)client時(shí)grpcs(也就是含有cred),就會(huì)在call中將其進(jìn)行設(shè)置-call.setCredentials(credentials)
同時(shí)旁赊,它有三個(gè)參數(shù):
* channel:就是實(shí)例化一個(gè)client的時(shí)候創(chuàng)建的channel桦踊。
* method:grpc方法。這里是/protos.Endorser/ProcessProposal
* options:一些參數(shù):包括hostname终畅、deadline和credential等籍胯。
找一下這個(gè)options的來(lái)源,其來(lái)源于makeUnaryRequest离福。

首先杖狼,其會(huì)調(diào)用makeUnaryRequest,check各種參數(shù)妖爷。
然后蝶涩,調(diào)用`var call = getCall(this.$channel, method, options);`獲取需要的rpc方法。然后創(chuàng)建一個(gè)emitter-`new ClientUnaryCall(call)`絮识。
之后绿聘,組裝一個(gè)client_batch,call并將其發(fā)送給server次舌,等待response熄攘。同時(shí)收到response后使用emitter將response的消息填充進(jìn)metadata。

打了一圈log垃它,在getCall中發(fā)現(xiàn):

Hostname undefined
deadline Infinity
parent undefined
credentials undefined
Init unary Call
ClientUnaryCall {
  domain: null,
  _events: {},
  _eventsCount: 0,
  _maxListeners: undefined,
  call: Call { channel_: Channel {} } }

為毛線都是undefined,貌似發(fā)現(xiàn)了問(wèn)題。
追蹤之后發(fā)現(xiàn)其來(lái)源于makeUnaryRequest的參數(shù)国拇,回頭check一下校驗(yàn)的代碼邏輯洛史。
首先,打印了這幾個(gè)參數(shù)發(fā)現(xiàn):

  • options:undefined酱吝,不應(yīng)該也殖。
  • metadata :在調(diào)用service的時(shí)候callback的function。
  • callback:undefined
  • argument:proposal的data
    這邊是校驗(yàn)的邏輯:
if (options instanceof Function) {
    callback = options;
    if (metadata instanceof Metadata) {
      options = {};
    } else {
      options = metadata;
      metadata = new Metadata();
    }
  } else if (metadata instanceof Function) {
    callback = metadata;
    metadata = new Metadata();
    options = {};
  }
  if (!metadata) {
    metadata = new Metadata();
  }
  if (!options) {
    options = {};
  }
  if (!((metadata instanceof Metadata) &&
    (options instanceof Object) &&
    (callback instanceof Function))) {
    throw new Error("Argument mismatch in makeUnaryRequest");
  }

按照獲取的數(shù)據(jù)來(lái)看务热,其走到了第二個(gè)分支:如果metadata是一個(gè)function忆嗜,則callback賦值,options為空對(duì)象崎岂。

經(jīng)過(guò)查看發(fā)現(xiàn)捆毫,Channel中應(yīng)該包含了addr和credential的相關(guān)信息。所以在options的時(shí)候就取消了冲甘。這里可以繼續(xù)digging绩卤。

Tips:一直忘記開啟grpc的詳細(xì)日志,在運(yùn)行node的程序中使用該環(huán)境變量---GRPC_TRACE=allGRPC_VERBOSITY=DEBUG(因?yàn)檫@個(gè)是給C++內(nèi)核用的江醇,所以應(yīng)該用export)
打開之后濒憋,發(fā)現(xiàn)有個(gè)問(wèn)題:

Cannot check peer: missing selected ALPN property

貌似是有關(guān)ALPN的錯(cuò)誤。server和client并不同時(shí)支持ALPN陶夜。

這里提一點(diǎn)凛驮,就是orderer的sendDeliver是用的stream,而不是普通GRPC条辟。

ALPN

openssl 1.0.2以上的版本支持了ALPN黔夭。
這個(gè)問(wèn)題是client發(fā)起的ssl握手,然后服務(wù)端并沒(méi)有將其APLN或者是NPN的版本發(fā)給客戶端捂贿。
然后纠修,這里提到,我們用GO的sdk(或者是peer的cli)進(jìn)行調(diào)用厂僧,就能夠連接扣草,并且功能執(zhí)行正常。

windows & linux

Grpc的ssl版本在windows和linux中使用的并不一樣颜屠。
windows使用的BoringSSL辰妙, Linux使用的是OpenSSL。BoringSSL有可能不能處理證書中domin為ip的情況(還未測(cè)試)甫窟。
如果發(fā)生了一些SSL的錯(cuò)誤密浑,可以直接使用openssl或者bssl的命令行進(jìn)行連接測(cè)試:

bssl s_client -connect 127.0.0.1:9110
openssl s_client -connect 127.0.0.1:9110 -showcerts

Tips:

  • BoringSSL已經(jīng)將所有的ECC算法移除,除了P-256和P-384粗井。同時(shí)其還有一些bug尔破。如果是在找不到原因可以去github上看看issue街图。

  • Grpc-node上build的時(shí)候有一個(gè)配置,如果該主機(jī)不支持ALPN就會(huì)rebuild項(xiàng)目排除ALPN的支持懒构。

{
  'variables': {
    'runtime%': 'node',
    # Some Node installations use the system installation of OpenSSL, and on
    # some systems, the system OpenSSL still does not have ALPN support. This
    # will let users recompile gRPC to work without ALPN.
    'grpc_alpn%': 'true',
    # Indicates that the library should be built with gcov.
    'grpc_gcov%': 'false',
    # Indicates that the library should be built with compatibility for musl
    # libc, so that it can run on Alpine Linux. This is only necessary if not
    # building on Alpine Linux
    'grpc_alpine%': 'false'
  }
  • node 程序運(yùn)行時(shí)可以添加環(huán)境變量:process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"餐济,強(qiáng)制取消對(duì)server證書的授權(quán)驗(yàn)證。
Grpc編譯(無(wú)ALPN的版本)

發(fā)現(xiàn)npm支持從源碼進(jìn)行安裝的方法-grpc npm胆剧。所以我們選擇先通過(guò)源碼安裝grpc然后在安裝其他的組件絮姆。

  1. 從github中獲取源碼。
git clone https://github.com/grpc/grpc.git

時(shí)間會(huì)很久秩霍。

  1. 更改grpc的源碼
    參考之前提到的那個(gè)配置項(xiàng)篙悯。這里將其改為false
'grpc_alpn%': 'false',

3 npm 編譯

npm install grpc --build-from-source 

但是在windows可能會(huì)出現(xiàn)問(wèn)題:node-grpc build on windows。如果在一開始(步驟比較靠前的地方)出現(xiàn)該錯(cuò)誤:

 ..
 Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch.
 WINDOWS_BUILD_WARNING
  "..\IMPORTANT: Due to https:\github.com\nodejs\node\issues\4932, to build this library on Windows, you must first remove C:\Users\jenkins\.node-gyp\4.4.0\include\node\openssl"
  ...
  ..

解決方法铃绒,就是把node-gyp的openssl刪掉(如果存在著會(huì)發(fā)現(xiàn)有沖突)鸽照,具體地址為:C:\Users\<username>\.node-gyp\<node_version>\include\node\openssl
詳細(xì)的解決方案可以看另外一個(gè)博客。

fabric go server端grpc

(待補(bǔ)充)

http2和http1

HTTP/2(超文本傳輸協(xié)議第2版匿垄,最初命名為 HTTP 2.0)移宅,是HTTP協(xié)議的的第二個(gè)主要版本起愈,使用于萬(wàn)維網(wǎng)摇零。HTTP/2 是 HTTP 協(xié)議自 1999 年 HTTP 1.1 發(fā)布后的首個(gè)更新锥咸,主要基于 SPDY 協(xié)議忌愚。HTTP/2 標(biāo)準(zhǔn)于2015年5月以 RFC 7540 正式發(fā)表夹纫,HTTP/2協(xié)議規(guī)范 rfc杉编。

為了實(shí)現(xiàn) HTTP 工作組設(shè)定的性能目標(biāo)秦效,HTTP/2 引入了一個(gè)新的二進(jìn)制分幀層礁竞,該層無(wú)法與之前的 HTTP/1.x 服務(wù)器和客戶端向后兼容铝条,因此協(xié)議的主版本提升到 HTTP/2靖苇。

http/2的優(yōu)點(diǎn)
  • 采用二進(jìn)制格式傳輸數(shù)據(jù),而非文本格式班缰。二進(jìn)制格式在協(xié)議的解析和優(yōu)化擴(kuò)展上帶來(lái)更多的優(yōu)勢(shì)和可能贤壁。

  • 對(duì)消息頭進(jìn)行壓縮傳輸,能夠節(jié)省消息頭占用的網(wǎng)絡(luò)的流量埠忘,而 HTTP 1.1 每次請(qǐng)求脾拆,都會(huì)攜帶大量冗余頭信息,浪費(fèi)了很多帶寬資源莹妒,頭壓縮能夠很好的解決該問(wèn)題名船。

  • 多路復(fù)用,就是多個(gè)請(qǐng)求都是通過(guò)一個(gè) TCP 連接并發(fā)完成旨怠, HTTP 1.1 雖然通過(guò) pipeline 也能并發(fā)請(qǐng)求渠驼,但是多個(gè)請(qǐng)求之間的響應(yīng)會(huì)被阻塞的,所以 pipeline 至今也沒(méi)有被普及應(yīng)用鉴腻,而 HTTP/2 做到了真正的并發(fā)請(qǐng)求迷扇,同時(shí)流還支持優(yōu)先級(jí)和流量控制百揭。

  • 服務(wù)器推送,服務(wù)端能夠更快的把資源推送給客戶端蜓席,例如服務(wù)端可以主動(dòng)把 JS 和 CSS 文件推送給客戶端信峻,而不需要客戶端解析 HTML 再發(fā)送這些請(qǐng)求,當(dāng)客戶端需要的時(shí)候瓮床,它已經(jīng)在客戶端了。

h2c 和h2

h2c:HTTP/2協(xié)議产镐,類型為clear text
h2:HTTP/2協(xié)議(加密)隘庄,例如構(gòu)建在SSL之上

gRPC

其是谷歌開發(fā)的一種RPC協(xié)議。主要用于建立在跨語(yǔ)言調(diào)用癣亚、數(shù)據(jù)壓縮的C/S鏈接上丑掺。gRPC是建立在HTTP/2之上進(jìn)行連接的,不管是cleartext(h2c述雾,未加密的數(shù)據(jù))還是TLS-encrypted(h2)的數(shù)據(jù)街州。
一個(gè)gRPC的call,其實(shí)是實(shí)現(xiàn)了一個(gè)HTTP的POST請(qǐng)求玻孟,對(duì)body的數(shù)據(jù)進(jìn)行了高效的編碼(當(dāng)然唆缴,肯定離不開谷歌的protobuf)。同樣gRPC的response也使用了同樣的編碼以及HTTP的數(shù)據(jù)規(guī)則(比如說(shuō)status code等)黍翎。
gRPC協(xié)議并不直接在HTTP/1.X之上傳輸面徽。gRPC使用HTTP/2是為了能夠支持多工(multiplexing)以及流式傳輸?shù)奶匦裕℉TTP/2)。

ALPN和NPN

NPN: Next Protocol Negotiation
ALPN:Application Layer Protocol Negotiation匣掸,ALPN wiki趟紊。

這兩個(gè)都是TLS的擴(kuò)展組件。因?yàn)?https, SPDY and HTTP/2協(xié)議都直接連通了443端口碰酝,所以ALPN和NPN讓應(yīng)用層協(xié)議能夠讓應(yīng)用層協(xié)議(plain http/1.1, SPDY or HTTP/2)轉(zhuǎn)化霎匈,連通構(gòu)建在SSL/TLS加密鏈接上的client和server。

SPDY使用NPN進(jìn)行轉(zhuǎn)化送爸,HTTP2使用ALPN進(jìn)行轉(zhuǎn)化铛嘱。其是建立在SSL/TLS的握手協(xié)議流程之上的。
NPN和ALPN都是在SSL/TLS建立鏈接中進(jìn)行干預(yù)碱璃。ALPN會(huì)將client支持的應(yīng)用層協(xié)議放在hello message中讓server選擇一個(gè)協(xié)議來(lái)建立安全鏈接弄痹。NPN則是server列舉,client進(jìn)行選擇嵌器。

我們可以通過(guò)該網(wǎng)站HTTP/2 Test查看瀏覽器針對(duì)各個(gè)協(xié)議的支持情況肛真。
我們也可以通過(guò)該命令行來(lái)查看是否支持APLN。

echo | openssl s_client -alpn h2 -connect yourdomain.com:443 | grep ALPN
//check the openssl verison
openssl verison

Tips: openssl版本一定要在1.0.2及其以上爽航。

Nginx支持HTTP/2 (ALPN)

在Nginx上開啟 HTTP/2 需要 Nginx 1.9.5 (或者是Nginx Plus R7)以上版本蚓让,并且需要 OpenSSL 版本在 1.0.2 以上乾忱。
因?yàn)?HTTP/2 不僅需要Web服務(wù)器還需要一個(gè)擴(kuò)展支持,目前可以用的有 ALPN 和 NPN 兩種(Chrome 已經(jīng)移除了對(duì) NPN 的支持)历极。只有 OpenSSL 1.0.2 以上版本才開始支持 ALPN 窄瘟。
如果系統(tǒng)版本不支持或者openssl過(guò)低,則需要下載openssl的高版本source code趟卸,然后使用--with-openssl顯示的指定openssl library的源碼位置蹄葱,然后rebuild整個(gè)Nginx項(xiàng)目。
各個(gè)操作系統(tǒng)版本針對(duì)openssl以及ALPN的支持情況:

image.png

指的注意的是锄列,nginx的一個(gè)端口不能綁定多個(gè)協(xié)議類型图云,比如說(shuō)HTTP/1(文本)和ClearText類型的HTTP/2(二進(jìn)制)綁定在同一個(gè)端口。建議如果針對(duì)clearText類型的數(shù)據(jù)邻邮,針對(duì)不同的協(xié)議版本綁定不同的監(jiān)聽端口竣况。因?yàn)閚ginx需要實(shí)現(xiàn)設(shè)置該端口支持哪一個(gè)版本的協(xié)議。
針對(duì)gRPC筒严,它主要使用HTTP/2當(dāng)做傳輸層來(lái)使用丹泉。
所以當(dāng)使用nginx來(lái)處理普通數(shù)據(jù)時(shí),一定要小心鸭蛙,其可能有很多種情況摹恨。
有三種方法可以讓一個(gè)HTTP server知道這個(gè)請(qǐng)求是http/2:

  1. 使用HTTP(原始文本)進(jìn)行HTTP/2的升級(jí)
  2. 使用HTTPS(加密數(shù)據(jù)),然后利用ALPN或者NPN轉(zhuǎn)化為TLS建立安全連接娶视。然后進(jìn)行HTTP的消息傳輸睬塌。
  3. 使用HTTP的原始文本,但是構(gòu)建HTTP/2的鏈接(雙方直接商議鏈接方案歇万,事先約定好)揩晴,直接使用HTTP/2。

nginx第一種不支持贪磺,并沒(méi)有一種能使用HTTP/2鏈接來(lái)進(jìn)行HTTP/1.1普通文本的數(shù)據(jù)傳輸(自動(dòng)轉(zhuǎn)化)硫兰,除非事先聲明,直接建立HTTP/2的鏈接寒锚。不能主動(dòng)探測(cè)(自動(dòng)識(shí)別劫映,并使用HTTP/2進(jìn)行連接)。當(dāng)然第二種方案刹前,例如GRPC的實(shí)現(xiàn)泳赋,也是可以的。GRPC會(huì)清楚的知道這個(gè)連接是否需要使用TLS并構(gòu)建彼此的鏈接喇喉,也就是是否使用HTTP/2的協(xié)議祖今。
但是GRPC并不是真正的HTTP。他只是使用了HTTP/2的the binary framing layer,構(gòu)建一個(gè)流控制的千诬、多通道的鏈接耍目,來(lái)進(jìn)行g(shù)RPC的消息的傳輸。它和Websocket實(shí)現(xiàn)HTTP TCP的鏈接來(lái)傳輸消息是一樣的徐绑,但是其并不是HTTP邪驮,只是用了HTTP的語(yǔ)法定義(規(guī)則或者說(shuō)協(xié)議規(guī)則)。讓他們看起來(lái)像是HTTP協(xié)議的數(shù)據(jù)傲茄。

Tips:Nginx利用HTTP server監(jiān)聽gRPC的請(qǐng)求毅访,同時(shí)使用grpc_pass來(lái)進(jìn)行分發(fā)代理。

參考鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盘榨,一起剝皮案震驚了整個(gè)濱河市俺抽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌较曼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件振愿,死亡現(xiàn)場(chǎng)離奇詭異捷犹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)冕末,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門萍歉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人档桃,你說(shuō)我怎么就攤上這事枪孩。” “怎么了藻肄?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蔑舞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我嘹屯,道長(zhǎng)攻询,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任州弟,我火速辦了婚禮钧栖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘婆翔。我一直安慰自己拯杠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布啃奴。 她就那樣靜靜地躺著潭陪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上畔咧,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天茎芭,我揣著相機(jī)與錄音,去河邊找鬼誓沸。 笑死梅桩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拜隧。 我是一名探鬼主播宿百,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼洪添!你這毒婦竟也來(lái)了垦页?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤干奢,失蹤者是張志新(化名)和其女友劉穎痊焊,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忿峻,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡薄啥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逛尚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垄惧。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绰寞,靈堂內(nèi)的尸體忽然破棺而出到逊,到底是詐尸還是另有隱情,我是刑警寧澤滤钱,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布觉壶,位于F島的核電站,受9級(jí)特大地震影響件缸,放射性物質(zhì)發(fā)生泄漏掰曾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一停团、第九天 我趴在偏房一處隱蔽的房頂上張望旷坦。 院中可真熱鬧,春花似錦佑稠、人聲如沸秒梅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捆蜀。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辆它,已是汗流浹背誊薄。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锰茉,地道東北人呢蔫。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像飒筑,于是被迫代替她去往敵國(guó)和親片吊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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