Retrofit 框架原理和源碼分析

一孕豹、簡單使用

具體使用流程和方法說明詳見:使用教程

簡單的代碼示例:

//步驟1:創(chuàng)建接口類
public interface WanAndroidService {
    @GET("article/list/{index}/json")
    Call<JsonObject> getArticles(@Path("index") int index);
}

//步驟2:構(gòu)建Retrofit實例
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://wanandroid.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

//步驟3:通過Retrofit.create方法創(chuàng)建接口類的代理對象
WanAndroidService wanAndroidService = retrofit.create(WanAndroidService.class);

//步驟4:調(diào)用接口代理對象方法返回Call類實例或者其他自定義請求類
Call<JsonObject> articles  = wanAndroidService.getArticles(0);

//步驟5:調(diào)用Call類實例的同步或者異步請求方法庆猫,發(fā)起網(wǎng)絡(luò)請求(.body()方法為獲取請求成功后返回的實體數(shù)據(jù)對象)
JsonObject body = articles.execute().body();

二登夫、原理分析

2.1拷邢、創(chuàng)建接口對象

2.1.1纸淮、源碼

步驟1和2比較簡單平斩,創(chuàng)建接口類,然后根據(jù)實際的情況構(gòu)建Retrofit類實例即可

源碼分析從步驟3Retrofit.create方法開始:

public <T> T create(final Class<T> service) {
    //校驗是否接口是否存在類型變量咽块,存在則拋出異常
    //如果Retrofit實例設(shè)置了立即校驗绘面,會先解析注解,將結(jié)果保存到緩存中備用(詳解loadServiceMethod方法分析)
    validateServiceInterface(service);
    return (T)
    //使用動態(tài)代理方法創(chuàng)建代理對象
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              //平臺信息類對象
              private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // 如果方法來自O(shè)bject類,則調(diào)用Object類方法的默認(rèn)實現(xiàn)揭璃,不做任何處理.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                //isDefaultMethod(method)晚凿,判斷是否是java8并且是默認(rèn)實現(xiàn)方法
                //如果是,則直接調(diào)用方法實現(xiàn)瘦馍,不做任何處理
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    //請求方法真正的調(diào)用邏輯
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

2.1.2歼秽、總結(jié)

  1. 通過JDK動態(tài)代理技術(shù)生成我們定義請求接口的代理對象。

  2. 接口方法的調(diào)用最終會調(diào)用到InvocationHandlerinvoke方法情组。

  3. invoke方法內(nèi)部接口是否合法(非泛型接口)燥筷,并且不是Object的方法,接口方法也不存在默認(rèn)實現(xiàn)(JAVA8開始支持)呻惕,則最終調(diào)用loadServiceMethod(method).invoke(args);方法開始解析封裝網(wǎng)絡(luò)請求荆责。

2.2、接口方法調(diào)用

按照2.1的結(jié)論亚脆,接口方法的調(diào)用最終會調(diào)用到loadServiceMethod(method).invoke(args);方法做院,具體源碼分析如下:

2.2.1、源碼

loadServiceMethod(method)

a. 解析注解濒持,生成ServiceMethod對象(loadServiceMethod(method)

ServiceMethod<?> loadServiceMethod(Method method) {
    //先從緩存獲取键耕,緩存獲取到直接返回
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      //double check 再檢查一次緩存
      result = serviceMethodCache.get(method);
      if (result == null) {
        //開始解析方法注解,生成ServiceMethod對象
        result = ServiceMethod.parseAnnotations(this, method);
        //緩存該方法對應(yīng)的ServiceMethod解析結(jié)果柑营,下次請求可以直接從緩存獲取
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

b. 解析注解屈雄,返回ServiceMethod對象(ServiceMethod.parseAnnotations(this, method)

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //生成RequestFactory對象,創(chuàng)建實例的同時會解析注解獲取網(wǎng)絡(luò)請求數(shù)據(jù)官套,解析的同時會校驗各個注解的合法性(比如請求方法注解必須是默認(rèn)GET/POST/...等等校驗)
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    //獲取返回參數(shù)類型
    Type returnType = method.getGenericReturnType();
    //校驗返回參數(shù)類型酒奶,類型不能為以下類型:
    //1、類型變量類型(T,E等等)奶赔、通配符表達(dá)式惋嚎、
    //2、參數(shù)類型<>中的參數(shù)類型不能存在類型變量或者通配符(即可以是List<String>站刑、不能是List<T>或者List<?>另伍、
    //3、泛型數(shù)組類型元素類型也不能存在類型變量或者通配符類型)
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    //返回類型也不能是void.class
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }
    //校驗通過調(diào)用HttpServiceMethod的parseAnnotations方法解析注解
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

c. 繼續(xù)解析注解绞旅,返回HttpServiceMethod對象(HttpServiceMethod.parseAnnotations(this, method, requestFactory)

//關(guān)鍵代碼
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ......
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;
    
    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      ......
    } else {
      //獲取方法的返回參數(shù)類型
      adapterType = method.getGenericReturnType();
    }
    //創(chuàng)建請求適配器(內(nèi)部通過CallAdpater.Factory創(chuàng)建摆尝,如果不自定義,并且方法返回值是Call因悲;則使用DefaultCallAdapterFactory創(chuàng)建CallAdapter堕汞;可以通過Retrofit配置新增Factory改變默認(rèn)行為)
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    ......

    //創(chuàng)建響應(yīng)數(shù)據(jù)轉(zhuǎn)換器(流程類似請求適配器創(chuàng)建)
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      //返回CallAdapted實例,傳遞的參數(shù)說明:
      //1囤捻、requestFactory:內(nèi)部保存注解解析到的請求方法臼朗,請求參數(shù)邻寿,URL等等數(shù)據(jù);
      //2视哑、callFactory:即OkHttpClient绣否;
      //3、responseConverter:數(shù)據(jù)解析轉(zhuǎn)換器挡毅;
      //4蒜撮、callAdapter:請求適配器,可以自定義實現(xiàn)線程切換等邏輯跪呈,Android默認(rèn)適配器功能是將異步請求響應(yīng)回調(diào)切換到主線程)
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      ......
    } else {
      ......
    }
  }

默認(rèn)的DefaultCallAdapterFactory請求適配器創(chuàng)建工廠源碼如下:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;

  //如果是Android 默認(rèn)傳入的是Platform.MainThreadExecutor實例(可以通過Retrofit配置修改)
  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //返回值類型不為Call.class段磨,則返回null
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    //檢查返回參數(shù)類型
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    //獲取Call<xxx>,xxx參數(shù)對應(yīng)的類型
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        //如果是Android耗绿,最終會調(diào)用到ExecutorCallbackCall里苹支,JAVA不做處理
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override
    public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {   //切換線程(默認(rèn)是切換到主線程)
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }

    @Override
    public boolean isExecuted() {
      return delegate.isExecuted();
    }

    @Override
    public Response<T> execute() throws IOException {
      return delegate.execute();
    }

    ......
  }
}

ServiceMehod.invoke(Object args)

接上一步,loadServiceMethod(method)返回的是個HttpServerMethod子類的實例误阻,invoke具體實現(xiàn)在HttpServerMethod中债蜜,源碼如下:

  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    //創(chuàng)建OkHttpCall實例
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    //調(diào)用adapt方法,Java最終會調(diào)用到CallAdapted的adapt方法中(Kotlin類似稍微有點區(qū)別)究反,最終會調(diào)用callAdapter的adapt方法寻定,源碼如下
    return adapt(call, args);
  }

  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      //callAdapter如上一步所述,默認(rèn)情況下Android平臺返回的是ExecutorCalbackCall(內(nèi)部默認(rèn)實現(xiàn)僅是將異步請求返回回調(diào)切回主線程)精耐,當(dāng)然我們可以通過配置callbackExecutor和新增自定義callAdapter的方式改變返回值或者默認(rèn)行為
      return callAdapter.adapt(call);
    }
  }

2.2.2狼速、總結(jié)

1、loadServiceMethod(method).invoke(args);調(diào)用結(jié)束卦停,默認(rèn)情況下返回的是一個OKHttpCall的實例(Android 平臺返回的是ExecutorCalbackCall向胡,它是OKHttpCall實例的裝飾器,擴(kuò)展了OKHttpCall異步請求回調(diào)處理邏輯)惊完。

2捷枯、可以通過Retrofit.BuildercallbackExecutor方法設(shè)置異步回調(diào)處理器的方式改變ExecutorCalbackCall默認(rèn)切換異步請求回調(diào)至主線程的行為。

3专执、可以通過Retrofit.BuilderaddCallAdapterFactory方法,新增適配器工廠郁油,改變和擴(kuò)展方法返回值以及方法執(zhí)行本股,異步請求回調(diào)線程切換等邏輯。

4桐腌、Retrofit+RxJava的模式拄显,就是通過上述3的方式,新增適配器工廠案站,從而達(dá)到改變方法返回值躬审,擴(kuò)展功能的目的。

2.3、發(fā)起網(wǎng)絡(luò)請求

接上面2.2邏輯承边,返回的是OkHttpCall(Android平臺默認(rèn)ExecutorCalbackCall僅僅是個裝飾器遭殉,最終方法調(diào)用也會調(diào)用到OkHttpCall里面)

(如果新增了CallAdapter,改變了返回值博助,最終還是需要調(diào)用到OkHttpCall方法來實現(xiàn)網(wǎng)絡(luò)請求险污,流程和默認(rèn)行為類似)

2.3.1、源碼

同步請求

Call.execute() 方法

  @Override
  public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      //一個Call只能執(zhí)行一次富岳,否則拋出一次
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      //獲取okhttp3.Call實例蛔糯,通過callFactory和requestFactory創(chuàng)建
      //最終會調(diào)用OkHttpClient.newCall(Request request)方法創(chuàng)建okhttp3.Call實例
      call = getRawCall();
    }

    if (canceled) {
      call.cancel();
    }
    //最終調(diào)用okhttp3.Call的execute方法發(fā)起同步請求
    //parseResponse解析響應(yīng)數(shù)據(jù)
    return parseResponse(call.execute());
  }

2.3.2、異步請求

Call.enqueue(final Callback\<T> callback) 方法

@Override
  public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      //一個Call只能執(zhí)行一次請求
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
      //獲取okhttp3.Call實例窖式,通過callFactory和requestFactory創(chuàng)建
      //最終會調(diào)用OkHttpClient.newCall(Request request)方法創(chuàng)建okhttp3.Call實例
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }
    //調(diào)用okhttp3.Call的enqueue異步方法發(fā)起異步請求
    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              //解析響應(yīng)數(shù)據(jù)
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              throwIfFatal(e);
              callFailure(e);
              return;
            }

            try {
              //回調(diào)響應(yīng)數(shù)據(jù)解析結(jié)果
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            //回調(diào)失敗
            callFailure(e);
          }

          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }
        });
  }

解析數(shù)據(jù)

OkHttpCall.parseResponse(okhttp3.Response rawResponse)方法

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // 刪除請求體主體數(shù)據(jù)蚁飒,以便后面使用無主體數(shù)據(jù)的Response傳遞響應(yīng)結(jié)果
    rawResponse =
        rawResponse
            .newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();

    int code = rawResponse.code();
    //判斷請求狀態(tài)碼
    if (code < 200 || code >= 300) {
      //非200,請求失敗
      try {
        //緩存錯誤響應(yīng)主體數(shù)據(jù)
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        //生成Retrofit的Response實例并返回
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      rawBody.close();
      //204萝喘,205判斷響應(yīng)體沒有主體內(nèi)容淮逻,直接返回成功無數(shù)據(jù)的Retrofit.Response實例
      return Response.success(null, rawResponse);
    }
    //使用Okio.buffer讀取響應(yīng)體主體數(shù)據(jù)到ExceptionCatchingResponseBody(ResponseBody的子類)實例中
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      //解析主體數(shù)據(jù),返回我們需要的數(shù)據(jù)實體對象
      T body = responseConverter.convert(catchingBody);
      //返回成功有數(shù)據(jù)的Retrofit.Response實例
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      catchingBody.throwIfCaught();
      throw e;
    }
  }

2.3.2蜒灰、總結(jié)

  1. 廣告請求最終會調(diào)用到okhttp3.Call的同步或者異步方法弦蹂。

  2. 通過OkHttpCall.parseResponse方法解析okhttp3.Call請求返回的okhttp3.Response響應(yīng)數(shù)據(jù)。最后會調(diào)用responseConverter.convert(轉(zhuǎn)換器的轉(zhuǎn)換方法)解析轉(zhuǎn)換不同的數(shù)據(jù)結(jié)構(gòu)强窖。

  3. 可以通過Retrofit.BuilderaddConverterFactory的方法凸椿,新增數(shù)據(jù)轉(zhuǎn)換器,支持解析不同的數(shù)據(jù)結(jié)構(gòu)翅溺。

  4. 解析數(shù)據(jù)之后脑漫,會將響應(yīng)結(jié)果,成功數(shù)據(jù)實體或者失敗數(shù)據(jù)包裝成Retrofit.Response的實例返回咙崎∮判遥可以通過Retrofit.Response類的code()或者isSuccessful()方法判斷是否成功。通過body()方法獲取請求成功狀態(tài)下的返回的數(shù)據(jù)實體(可能為空)褪猛。

  5. 如果不新增ConverterFactory网杆,默認(rèn)情況只能返回okhttp3.ResponseBody類的對象實例。即Retrofit.Response.body()獲取的實例只能是okhttp3.ResponseBody類的對象(java8+也可以是Optional)伊滋,同時定義接口方法的返回值實際參數(shù)類型只能是okhttp3.ResponseBody.class碳却。

三、最后總結(jié)

  • Retrofit框架讓開發(fā)者可以通過接口注解的方式描述網(wǎng)絡(luò)請求笑旺,然后通過JDK動態(tài)代理的方式真正實現(xiàn)接口方法調(diào)用邏輯昼浦。方法的調(diào)用會對接口注解進(jìn)行解析,最后將網(wǎng)絡(luò)請求解析結(jié)果和相關(guān)配置封裝到OkHttpCall中筒主。

  • OkHttpCall調(diào)用方法開始網(wǎng)絡(luò)請求关噪,最終還是會調(diào)用okHttp3.call類中的同步或者異步請求方法鸟蟹,實現(xiàn)真正的網(wǎng)絡(luò)請求(即網(wǎng)絡(luò)請求的實現(xiàn)還是通過OkHttp框架實現(xiàn)的)。

  • CallAdapter數(shù)據(jù)請求適配器是為了擴(kuò)展OkHttpCall的功能使兔,最后還是會通過OkHttpCall來組織網(wǎng)絡(luò)請求建钥。

  • ConverAdapter數(shù)據(jù)轉(zhuǎn)換器的作用是在請求成功之后,將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成我們想要是實體對象火诸。

四锦针、關(guān)聯(lián)知識

Java 動態(tài)代理知識

Retrofit 框架使用

Java Type 知識說明

五、參考文章

Android Retrofit 工作原理解析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末置蜀,一起剝皮案震驚了整個濱河市奈搜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盯荤,老刑警劉巖馋吗,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異秋秤,居然都是意外死亡宏粤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門灼卢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绍哎,“玉大人,你說我怎么就攤上這事鞋真〕缪撸” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵涩咖,是天一觀的道長海诲。 經(jīng)常有香客問我,道長檩互,這世上最難降的妖魔是什么特幔? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮闸昨,結(jié)果婚禮上蚯斯,老公的妹妹穿的比我還像新娘。我一直安慰自己饵较,他們只是感情好溉跃,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著告抄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嵌牺。 梳的紋絲不亂的頭發(fā)上打洼,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天龄糊,我揣著相機(jī)與錄音,去河邊找鬼募疮。 笑死炫惩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阿浓。 我是一名探鬼主播他嚷,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芭毙!你這毒婦竟也來了筋蓖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤退敦,失蹤者是張志新(化名)和其女友劉穎粘咖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侈百,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡瓮下,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了钝域。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讽坏。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖例证,靈堂內(nèi)的尸體忽然破棺而出路呜,到底是詐尸還是另有隱情,我是刑警寧澤战虏,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布拣宰,位于F島的核電站,受9級特大地震影響烦感,放射性物質(zhì)發(fā)生泄漏巡社。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一手趣、第九天 我趴在偏房一處隱蔽的房頂上張望晌该。 院中可真熱鬧,春花似錦绿渣、人聲如沸朝群。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姜胖。三九已至,卻和暖如春淀散,著一層夾襖步出監(jiān)牢的瞬間右莱,已是汗流浹背蚜锨。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留慢蜓,地道東北人亚再。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像晨抡,于是被迫代替她去往敵國和親氛悬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

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