OkHttp網絡框架設計

OSI七層模型介紹社裆,TCP/IP模型介紹,HTTP協(xié)議格式介紹

OSI七層模型

應用層------可見的終端(瀏覽器)

表示層------計算機識別的信息轉變人可以識別的信息

回話層------傳輸端口和接受端口的建立回話

傳輸層------傳輸數(shù)據的協(xié)議與端口

網絡層------IP地址

數(shù)據鏈路層------交換機傳輸

物理層------具體物理設備

TCP/IP模型?

應用層----http https REST REMT

傳輸層----Socket

應用層

主機至網絡層

HTTP GET Request

發(fā)起請求:1.請求頭之請求行 2.? ? 請求頭之請求屬性集

HTTP POST Request

發(fā)起請求:1.請求頭之請求行? 2. 請求頭之請求屬性集? 3.請求體長度 4.請求的類型

OKHttp主線流程的源碼解讀

OKHttp的使用:

OKHttpClient------Request------newCall 執(zhí)行RealCall.enqueue(){不能重復執(zhí)行}------

Dispatcher.enqueue(AsyncCall:if先加入運行隊列攒射,執(zhí)行異步任務 else 直接加入等待隊列)------AsyncCall.excute()區(qū)分責任劃分判斷是用戶導致還是OKHttp導致的,責任鏈模式,多個攔截器,返回response别渔。

OKHttp源碼解讀之線程池詳解

線程池的作用就是避免重復創(chuàng)建和銷毀線程耗費內存

ThreadPoolExecutorexecutor=new ThreadPoolExecutor(0,Integer.MAX_VALUE,60, TimeUnit.MILLISECONDS,new LinkedBlockingDeque());

參數(shù)一:corePoolSize 核心線程數(shù)

參數(shù)二:maximumPoolSize 最大線程數(shù)

參數(shù)三/四:時間數(shù)值 keepAliveTime? ?單位unit 時分秒

? ? ? ? ? ? ? ? ? ? 正在執(zhí)行的任務數(shù)量>corePoolSize---->參數(shù)三、四才會起作用

? ? ? ? ? ? ? ? ? ? 任務執(zhí)行完畢后惧互,閑置超過參數(shù)三、四設置的時間喇伯,才會回收線程喊儡,在這段時間以內就會復用線程。

參數(shù)五:workQueue隊列 會把超出的任務加入隊列稻据,緩存起來

OkHttp里面的線程池:

public synchronized ExecutorServiceexecutorService() {

if (executorService ==null) {

executorService =new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,

? ? ? ? new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));

? }

return executorService;

}

有源碼可知:OkHttp里面的線程池采用的是緩存策略艾猜,

OkHttp里面線程池,采用的是緩存方案+線程工廠+非守護線程

將核心線程設為0捻悯,只要runnable>1匆赃,60秒之內就會復用線程,超過60秒回收線程今缚。

OKHttp源碼閱讀之構建者模式/責任鏈模式

構建著模式:鏈式編程結構清晰(方法返回client本身)算柳,通過Builder來實現(xiàn)參數(shù)的復制

責任鏈模式:將不同的模塊分塊,集成共同的接口姓言,設置一個manager也集成共同的接口瞬项,將不同的模塊添加到集合中蔗蹋,通過重寫共同接口的方法,達到在集合中不斷執(zhí)行不同模塊的功能囱淋,如果不符合條件就停止執(zhí)行猪杭。

OKHttp 手寫實現(xiàn)之整體框架搭建

根據OKHttp的源碼創(chuàng)建自己的OkHttpClient2??Request2?Call2??CallBack2.....

public void uesMyOkHttp(View view) {

????OkHttpClient2 okHttpClient2 =new OkHttpClient2.Builder().build();

? ? Request2 request2 =new Request2.Builder().url("https://www.baidu.com").build();

? ? Call2 call = okHttpClient2.newCall(request2);

? ? call.enqueue(new CallBack2() {

????@Override

? ? ? ? public void onFailure(Call2 call, IOException e) {

????Log.e("eeeeeee",e.getMessage());

? ? ? ? }

@Override

? ? ? ? public void onResponse(Call2 call, Response2 response)throws IOException {

Log.e("eeeeeee",response.getBody());

? ? ? ? }

});

}

OkHttpClient2??Request2一樣,都是采用創(chuàng)建者模式妥衣,鏈式編程可以傳入自定義的參數(shù)皂吮、

public class OkHttpClient2 {

private Dispacher2dispacher2;

? ? private boolean isCancle;

? ? private Stringurl;

? ? private int recount;

? ? public int getRecount() {

return recount;

? ? }

public OkHttpClient2() {

this(new Builder());

? ? }

public OkHttpClient2(Builder builder) {

this.dispacher2 = builder.dispacher2;

? ? ? ? this.isCancle = builder.isCancle;

? ? ? ? this.url = builder.url;

? ? ? ? this.recount=builder.recount;

? ? }

public boolean getCanle() {

return isCancle;

? ? }

public static final class Builder {

private Stringurl;

? ? ? ? private Dispacher2dispacher2;

? ? ? ? private boolean isCancle;

? ? ? ? int recount =3;//默認重試3次

? ? ? ? public Builder() {

dispacher2 =new Dispacher2();

? ? ? ? }

public OkHttpClient2build() {

return new OkHttpClient2(this);

? ? ? ? }

public BuildersetCount(int recount) {

this.recount = recount;

return this;

? ? ? ? }

public Buildercancle() {

isCancle =true;

return this;

? ? ? ? }

public Builderdispacher(Dispacher2 dispacher2) {

this.dispacher2 = dispacher2;

return this;

? ? ? ? }

public Builderurl(String url) {

this.url = url;

return this;

? ? ? ? }

}

public Call2newCall(Request2 request2) {

return new RealCall2(request2, this);

? ? }

public Dispacher2dispacher() {

return dispacher2;

? ? }

}


public class Request2 {

public static final StringGET ="GET";

? ? public static final StringPOST ="POST";

? ? private Stringurl;

? ? public StringgetUrl() {

return url;

? ? }

public StringgetRequestMethod() {

return requestMethod;

? ? }

public MapgetmHeadList() {

return mHeadList;

? ? }

private StringrequestMethod =GET;

? ? private MapmHeadList =new HashMap<>();

? ? public Request2() {

this(new Builder());

? ? }

public Request2(Builder builder) {

this.url = builder.url;

? ? ? ? this.requestMethod = builder.requestMethod;

? ? ? ? this.mHeadList = builder.mHeadList;

? ? }

public static final class Builder {

private Stringurl;

? ? ? ? private StringrequestMethod =GET;

? ? ? ? private MapmHeadList =new HashMap<>();

? ? ? ? public Request2build() {

return new Request2(this);

? ? ? ? }

public Builderget() {

requestMethod =GET;

return this;

? ? ? ? }

public Builderpost() {

requestMethod =POST;

return this;

? ? ? ? }

public BuilderaddHead(String key, String value) {

mHeadList.put(key, value);

return this;

? ? ? ? }

public Builderurl(String url) {

this.url = url;

return this;

? ? ? ? }

}

}

定義一個接口Call2

public interface Call2 {

void enqueue(CallBack2 responseCallback);

}

定義一個RealCall實現(xiàn)Call2

public class RealCall2implements Call2 {

private boolean excuted;

? ? private Request2request2;

? ? private OkHttpClient2okHttpClient2;

? ? public boolean isExcuted() {

return excuted;

? ? }

public Request2getRequest2() {

return request2;

? ? }

public OkHttpClient2getOkHttpClient2() {

return okHttpClient2;

? ? }

public RealCall2(Request2 request2, OkHttpClient2 okHttpClient2) {

this.request2 = request2;

? ? ? ? this.okHttpClient2 = okHttpClient2;

? ? }

@Override

? ? public void enqueue(CallBack2 responseCallback) {

synchronized (this) {

if (excuted) {

excuted =true;

? ? ? ? ? ? ? ? throw new IllegalArgumentException("Already Executed");

? ? ? ? ? ? }

}

okHttpClient2.dispacher().enqueue(new AsyncCall2(responseCallback));

? ? }

public final class AsyncCall2implements Runnable {

private CallBack2callBack2;

? ? ? ? public Request2getRequest2() {

return RealCall2.this.request2;

? ? ? ? }

public AsyncCall2(CallBack2 callBack2) {

this.callBack2 = callBack2;

? ? ? ? }

@Override

? ? ? ? public void run() {

boolean signalledCallback =false;

? ? ? ? ? ? try {

Response2 response = getResponseWithInterceptorChain();

? ? ? ? ? ? ? ? if (okHttpClient2.getCanle()) {

signalledCallback =true;

? ? ? ? ? ? ? ? ? ? callBack2.onFailure(RealCall2.this, new IOException("用戶取消了 請求"));

? ? ? ? ? ? ? ? }else {

signalledCallback =true;

? ? ? ? ? ? ? ? ? ? callBack2.onResponse(RealCall2.this, response);

? ? ? ? ? ? ? ? }

}catch (IOException e) {

//責任的劃分

? ? ? ? ? ? ? ? if (signalledCallback) {//用戶的操作

? ? ? ? ? ? ? ? ? ? System.out.println("用戶再使用過程中? 出錯了");

? ? ? ? ? ? ? ? }else {

callBack2.onFailure(RealCall2.this, new IOException("OKHttp getResponseWithInterceptorChain錯誤 e:" + e.toString()));

? ? ? ? ? ? ? ? }

}finally {//回收

? ? ? ? ? ? ? ? okHttpClient2.dispacher().finished(this);

? ? ? ? ? ? }

}

private Response2getResponseWithInterceptorChain()throws IOException {

Response2 response2 =new Response2();

? ? ? ? ? ? response2.setBody("流程走通");

? ? ? ? ? ? return response2;

? ? ? ? }

}

}

通過構造參數(shù)將前面的client和request傳到RealCall里面?

重寫enqueue方法,執(zhí)行dispacher里面的enqueue方法

@Override

public void enqueue(CallBack2 responseCallback) {

synchronized (this) {

if (excuted) {

excuted =true;

? ? ? ? ? ? throw new IllegalArgumentException("Already Executed");

? ? ? ? }

}

okHttpClient2.dispacher().enqueue(new AsyncCall2(responseCallback));

}

創(chuàng)建Dipacher2 在enqueue方法里面判斷是將任務添加到執(zhí)行隊列還是等待隊列税手,添加到執(zhí)行隊列后利用線程池執(zhí)行任務涮较。? ??

通過finally {//回收

? ? okHttpClient2.dispacher().finished(this);

}

將等待隊列的任務便利執(zhí)行完畢。冈止,還將run方法里面責任進行劃分狂票,明確是OK HTTP本身的責任還是使用者的責任,callBack2執(zhí)行callback熙暴,將執(zhí)行情況返回給頁面闺属,

Response2 response = getResponseWithInterceptorChain();通過責任鏈模式將response返回,詳細情況在下面手寫socket

public class Dispacher2 {

private int maxRequests =64;//同時訪問任務周霉,最大數(shù)量是64

? ? private int maxRequestsPerHost =5;//同時訪問同一個服務器域名掂器,最大限制

? ? private DequerunningAsyncCalls =new ArrayDeque<>();

? ? private DequereadyAsyncCalls =new ArrayDeque<>();

? ? public void enqueue(RealCall2.AsyncCall2 call) {

if (runningAsyncCalls.size()

runningAsyncCalls.add(call);//加入運行隊列

? ? ? ? ? ? executorService().execute(call);//然后再執(zhí)行

? ? ? ? }else {

readyAsyncCalls.add(call);//加入等待隊列

? ? ? ? }

}

private ExecutorexecutorService() {

ExecutorService executorService =new ThreadPoolExecutor(0, 64, 60l, TimeUnit.MILLISECONDS, new SynchronousQueue(), new ThreadFactory() {

@Override

? ? ? ? ? ? public ThreadnewThread(Runnable r) {

Thread thread =new Thread(r);

? ? ? ? ? ? ? ? thread.setName("自定義的線程。俱箱。国瓮。");

? ? ? ? ? ? ? ? thread.setDaemon(false);

? ? ? ? ? ? ? ? return thread;

? ? ? ? ? ? }

});

? ? ? ? return executorService;

? ? }

/**

* 判斷AsyncCall2中的Host,在運行的隊列中,計數(shù)狞谱,然后返回

*/

? ? private int runningCallsForHost(RealCall2.AsyncCall2 call) {

int count =0;

? ? ? ? if (runningAsyncCalls.isEmpty()) {

return 0;

? ? ? ? }

SocketRequestSever src =new SocketRequestSever();

? ? ? ? //遍歷運行隊伍里面的所有人物乃摹,取出任務host==call.host +1

? ? ? ? for (RealCall2.AsyncCall2 runningAsyncCall :runningAsyncCalls) {

if (src.getHost(runningAsyncCall.getRequest2()).equals(call.getRequest2())) {

count++;

? ? ? ? ? ? }

}

return count;

? ? }

public void finished(RealCall2.AsyncCall2 call2) {

//當前運行隊列

? ? ? ? runningAsyncCalls.remove(call2);

? ? ? ? //等待隊列為空就返回

? ? ? ? if (readyAsyncCalls.isEmpty()) {

return;

? ? ? ? }

//把等待隊列任務移動到運行隊列

? ? ? ? for (RealCall2.AsyncCall2 readyAsyncCall :readyAsyncCalls) {

readyAsyncCalls.remove(readyAsyncCall);//殺出等待隊列的任務

? ? ? ? ? ? runningAsyncCalls.add(readyAsyncCall);

? ? ? ? ? ? executorService().execute(readyAsyncCall);

? ? ? ? }

}

}

創(chuàng)建CallBack2和AsyncCall2

public interface CallBack2 {

????void onFailure(Call2 call, IOException e);

? ? void onResponse(Call2 call, Response2 response)throws IOException;

}

public final class AsyncCall2implements Runnable {

private CallBack2callBack2;

? ? ? ? public Request2getRequest2() {

return RealCall2.this.request2;

? ? ? ? }

public AsyncCall2(CallBack2 callBack2) {

this.callBack2 = callBack2;

? ? ? ? }

@Override

? ? ? ? public void run() {

boolean signalledCallback =false;

? ? ? ? ? ? try {

Response2 response = getResponseWithInterceptorChain();

? ? ? ? ? ? ? ? if (okHttpClient2.getCanle()) {

signalledCallback =true;

? ? ? ? ? ? ? ? ? ? callBack2.onFailure(RealCall2.this, new IOException("用戶取消了 請求"));

? ? ? ? ? ? ? ? }else {

signalledCallback =true;

? ? ? ? ? ? ? ? ? ? callBack2.onResponse(RealCall2.this, response);

? ? ? ? ? ? ? ? }

}catch (IOException e) {

//責任的劃分

? ? ? ? ? ? ? ? if (signalledCallback) {//用戶的操作

? ? ? ? ? ? ? ? ? ? System.out.println("用戶再使用過程中? 出錯了");

? ? ? ? ? ? ? ? }else {

callBack2.onFailure(RealCall2.this, new IOException("OKHttp getResponseWithInterceptorChain錯誤 e:" + e.toString()));

? ? ? ? ? ? ? ? }

}finally {//回收

? ? ? ? ? ? ? ? okHttpClient2.dispacher().finished(this);

? ? ? ? ? ? }

}

private Response2getResponseWithInterceptorChain()throws IOException {

Response2 response2 =new Response2();

? ? ? ? ? ? response2.setBody("流程走通");

? ? ? ? ? ? return response2;

? ? ? ? }

}
自定義攔截器

首先創(chuàng)建Interceptor2接口

public interface Interceptor2 {

Response2doNext(Chain2 chain2)throws IOException;

}

創(chuàng)建一個充實攔截器ReRequestInterceptor?

public class ReRequestInterceptor implements Interceptor2 {

@Override

? ? public Response2doNext(Chain2 chain2)throws IOException {

ChainManager chainManager = (ChainManager) chain2;

? ? ? ? RealCall2 realCall2 = chainManager.getCall2();

? ? ? ? OkHttpClient2 okHttpClient2 = realCall2.getOkHttpClient2();

? ? ? ? IOException ioException =null;

? ? ? ? if (okHttpClient2.getRecount() !=0) {

for (int i =0; i < okHttpClient2.getRecount(); i++) {

try {

Response2 response2 = chain2.getResponse(chainManager.getRequest());

? ? ? ? ? ? ? ? ? ? return response2;

? ? ? ? ? ? ? ? }catch (IOException e) {

ioException = e;

? ? ? ? ? ? ? ? }

}

}

throw ioException;

? ? }

}

創(chuàng)建Chain2接口

public interface Chain2 {

Request2getRequest();

? ? Response2getResponse(Request2 request2)throws IOException;

}


創(chuàng)建ChainManager,將攔截器存放到集合中跟衅,循環(huán)便利

public class ChainManager implements Chain2 {

private final Listinterceptors;

? ? private int index;

? ? private final Request2request2;

? ? private final RealCall2call2;

? ? public? ListgetInterceptors() {

return interceptors;

? ? }

public int getIndex() {

return index;

? ? }

public? RealCall2getCall2() {

return call2;

? ? }

public ChainManager(List interceptors, int index, Request2 request2, RealCall2 call2) {

this.interceptors = interceptors;

? ? ? ? this.index = index;

? ? ? ? this.request2 = request2;

? ? ? ? this.call2 = call2;

? ? }

@Override

? ? public Request2getRequest() {

return request2;

? ? }

@Override

? ? public Response2getResponse(Request2 request2)throws IOException {

if(index>interceptors.size())throw new AssertionError();

? ? ? ? if(interceptors.isEmpty())throw new IOException("interceptor is empty");

? ? ? ? ChainManager chainManager=new ChainManager(interceptors,index++,request2,call2);

? ? ? ? Interceptor2 interceptor=interceptors.get(index);

? ? ? ? Response2 response2=interceptor.doNext(chainManager);

? ? ? ? return response2;

? ? }

}


OKHttp 手寫實現(xiàn)之socket請求與響應

創(chuàng)建SocketRequestServer

public class SocketRequestServer {

? ? private final String K = " ";

? ? private final String VIERSION = "HTTP/1.1";

? ? private final String GRGN = "\r\n";

? ? /**

? ? * todo 通過Request對象孵睬,尋找到域名HOST

? ? * @param request2

? ? * @return

? ? */

? ? public String getHost(Request2 request2) {

? ? ? ? try {

? ? ? ? ? ? // http://restapi.amap.com/v3/weather/weatherInfo?city=110101&key=13cb58f5884f9749287abbead9c658f2

? ? ? ? ? ? URL url = new URL(request2.getUrl());

? ? ? ? ? ? return url.getHost(); // restapi.amap.com

? ? ? ? } catch (MalformedURLException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return null;

? ? }

? ? /**

? ? * todo 端口

? ? * @param request2

? ? * @return

? ? */

? ? public int getPort(Request2 request2) {

? ? ? ? try {

? ? ? ? ? ? URL url = new URL(request2.getUrl());

? ? ? ? ? ? int port = url.getPort();

? ? ? ? ? ? return port == -1 ? url.getDefaultPort() : port;

? ? ? ? } catch (MalformedURLException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return -1;

? ? }

? ? /**

? ? * todo 獲取請求頭的所有信息

? ? * @param request2

? ? * @return

? ? */

? ? public String getRequestHeaderAll(Request2 request2) {

? ? ? ? // 得到請求方式

? ? ? ? URL url = null;

? ? ? ? try {

? ? ? ? ? ? url = new URL(request2.getUrl());

? ? ? ? } catch (MalformedURLException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? String file = url.getFile();

? ? ? ? // TODO 拼接 請求頭 的 請求行? GET /v3/weather/weatherInfo?city=110101&key=13cb58f5884f9749287abbead9c658f2 HTTP/1.1\r\n

? ? ? ? StringBuffer stringBuffer = new StringBuffer();

? ? ? ? stringBuffer.append(request2.getRequestMethod()) // GET or POST

? ? ? ? .append(K)

? ? ? ? .append(file)

? ? ? ? .append(K)

? ? ? ? .append(VIERSION)

? ? ? ? .append(GRGN);

? ? ? ? // TODO 獲取請求集 進行拼接

? ? ? ? /**

? ? ? ? * Content-Length: 48\r\n

? ? ? ? * Host: restapi.amap.com\r\n

? ? ? ? * Content-Type: application/x-www-form-urlencoded\r\n

? ? ? ? */

? ? ? ? if (!request2.getmHeaderList().isEmpty()) {

? ? ? ? ? ? Map<String,String> mapList = request2.getmHeaderList();

? ? ? ? ? ? for (Map.Entry<String, String> entry: mapList.entrySet()) {

? ? ? ? ? ? ? ? stringBuffer.append(entry.getKey())

? ? ? ? ? ? ? ? ? ? ? ? .append(":").append(K)

? ? ? ? ? ? ? ? ? ? ? ? .append(entry.getValue())

? ? ? ? ? ? ? ? ? ? ? ? .append(GRGN);

? ? ? ? ? ? }

? ? ? ? ? ? // 拼接空行,代表下面的POST伶跷,請求體了

? ? ? ? ? ? stringBuffer.append(GRGN);

? ? ? ? }

? ? ? ? // TODO POST請求才有 請求體的拼接

? ? ? ? if ("POST".equalsIgnoreCase(request2.getRequestMethod())) {

? ? ? ? ? ? stringBuffer.append(request2.getRequestBody2().getBody()).append(GRGN);

? ? ? ? }

? ? ? ? return stringBuffer.toString();

? ? }

}


在getResponseWithInterceptorChain()里面添加

private Response2 getResponseWithInterceptorChain() throws IOException {

//? ? ? ? ? ? Response2 response2 = new Response2();

//? ? ? ? ? ? response2.setBody("流程走通....");

//? ? ? ? ? ? return response2;

? ? ? ? ? ? List<Interceptor2> interceptor2List = new ArrayList<>();

? ? ? ? ? ? interceptor2List.add(new ReRequestInterceptor()); // 重試攔截器

? ? ? ? ? ? interceptor2List.add(new RequestHeaderInterceptor()); // 請求頭攔截器

? ? ? ? ? ? interceptor2List.add(new ConnectionServerInterceptor()); // 連接服務器的攔截器

? ? ? ? ? ? ChainManager chainManager = new ChainManager(interceptor2List, 0, request2, RealCall2.this);

? ? ? ? ? ? return chainManager.getResponse(request2); // 最終返回的Response

? ? ? ? }

? ? }

url 統(tǒng)一資源定位符

url.getHost()? 域名

url.getPort()? 端口

url.getFile()? 傳輸文件

url.getProtocol()? 協(xié)議

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末掰读,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叭莫,更是在濱河造成了極大的恐慌蹈集,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雇初,死亡現(xiàn)場離奇詭異拢肆,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門善榛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辩蛋,“玉大人,你說我怎么就攤上這事移盆〉吭海” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵咒循,是天一觀的道長据途。 經常有香客問我,道長叙甸,這世上最難降的妖魔是什么颖医? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮裆蒸,結果婚禮上熔萧,老公的妹妹穿的比我還像新娘。我一直安慰自己僚祷,他們只是感情好佛致,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辙谜,像睡著了一般俺榆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上装哆,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天罐脊,我揣著相機與錄音,去河邊找鬼蜕琴。 笑死萍桌,一個胖子當著我的面吹牛,可吹牛的內容都是我干的奸绷。 我是一名探鬼主播梗夸,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼号醉!你這毒婦竟也來了?” 一聲冷哼從身側響起辛块,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤畔派,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后润绵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體线椰,經...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年尘盼,在試婚紗的時候發(fā)現(xiàn)自己被綠了憨愉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烦绳。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖配紫,靈堂內的尸體忽然破棺而出径密,到底是詐尸還是另有隱情,我是刑警寧澤躺孝,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布享扔,位于F島的核電站,受9級特大地震影響植袍,放射性物質發(fā)生泄漏惧眠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一于个、第九天 我趴在偏房一處隱蔽的房頂上張望氛魁。 院中可真熱鬧,春花似錦厅篓、人聲如沸秀存。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽应又。三九已至,卻和暖如春乏苦,著一層夾襖步出監(jiān)牢的瞬間株扛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工汇荐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洞就,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓掀淘,卻偏偏與公主長得像旬蟋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子革娄,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容