前端構(gòu)建 DevOps :構(gòu)建篇-jenkins

前言

基礎(chǔ)平臺(tái)搭建上篇 介紹項(xiàng)目流程設(shè)計(jì)耳舅、數(shù)據(jù)庫(kù)搭建、jwt 登錄等模塊

基礎(chǔ)平臺(tái)搭建中篇 介紹分支管理設(shè)計(jì)营搅、webSocket 基礎(chǔ)模塊

基礎(chǔ)平臺(tái)搭建下篇 介紹流程管理涵防、提測(cè)相關(guān)基礎(chǔ)模塊

基礎(chǔ)篇主要介紹了項(xiàng)目管理流程的基礎(chǔ)架構(gòu)設(shè)計(jì)與一些基本的 node 開(kāi)發(fā)铜幽,本篇開(kāi)始構(gòu)建系統(tǒng)系列驴剔,簡(jiǎn)單講述一下 jenkins 與項(xiàng)目管理系統(tǒng)的配合

Jenkins

Jenkins 是什么

Jenkins 是一個(gè)開(kāi)源的、提供友好操作界面的持續(xù)集成(CI)工具跋核,起源于 Hudson(Hudson 是商用的)岖瑰,主要用于持續(xù)、自動(dòng)的構(gòu)建/測(cè)試軟件項(xiàng)目砂代、監(jiān)控外部任務(wù)的運(yùn)行蹋订。Jenkins 用 Java 語(yǔ)言編寫(xiě),可在 Tomcat 等流行的 servlet 容器中運(yùn)行刻伊,也可獨(dú)立運(yùn)行露戒。通常與版本管理工具(SCM)、構(gòu)建工具結(jié)合使用捶箱。常用的版本控制工具有 SVN智什、GIT,構(gòu)建工具有 Maven丁屎、Ant荠锭、Gradle。

在此項(xiàng)目中晨川,Jenkins 作為主要構(gòu)建工具來(lái)搭配使用

Jenkins 安裝(踩坑合集)

一般我的博客是不會(huì)介紹具體安裝過(guò)程的节沦,但是這個(gè)讓我踩了一天的坑键思,還是列一下吧(主要是 windows 踩坑多)

Windows 環(huán)境

直接下載 Jenkins 安裝包,再下載一個(gè) JAVA SDK 甫贯,直接點(diǎn)擊安裝一把梭。

安裝完之后需要密碼看蚜,64 位系統(tǒng)的同學(xué)叫搁,記得不要去 sys32 目錄找,雖然網(wǎng)頁(yè)顯示的路徑是 sys32

但是 C:\Windows\SysWOW64\config\systemprofile\AppData\Local\Jenkins.jenkins 這個(gè)才是正確的路徑

不建議用 windows 版本供炎,再不濟(jì)搞個(gè)虛擬機(jī)渴逻,體驗(yàn)效果翻倍

Mac 環(huán)境

建議用 brew 直接下載,比較容易管理

brew 安裝過(guò)慢的解決方案:點(diǎn)擊這里

插件安裝速度過(guò)慢

  1. 先進(jìn)入 http://ip:10086/pluginManager/advanced 插件管理頁(yè)音诫,將地址從 https://updates.jenkins.io/update-center.json 換成 http://mirror.xmission.com/jenkins/updates/update-center.json惨奕,可以提高下載速度。

  2. 修改 Jenkins/updates/default.json 配置

替換 updates.jenkins-ci.org/download 為 mirrors.tuna.tsinghua.edu.cn/jenkins

替換 www.google.comwww.baidu.com

完了直接 http://ip:10086/restart 重啟

docer 安裝不建議竭钝,高射炮打蚊子的事情少干

pipeline 腳本

先簡(jiǎn)單介紹一下

聯(lián)系:node, agent 以及 slave 都用來(lái)指被 Jenkins master 管理的用來(lái)執(zhí)行 Jenkins jobs 的服務(wù)器梨撞。

區(qū)別:agents 用在表述性 pipeline 中,可以不僅僅是 nodes ,還可以是 docker container 等香罐。node(這個(gè)不是那個(gè) js node) 用在腳本化 pipeline 中卧波。

image

直接上 node pipeline 腳本,強(qiáng)擼一把(簡(jiǎn)單先跑起來(lái)庇茫,后期需要優(yōu)化的地方還是很多的)

配置參數(shù):

名稱 描述
PROJECT_NAME 工程名稱
PROJECT_VERSION 工程版本號(hào)
PROJECT_GIT_PATH 工程地址
BRANCH_NAME 工程分支
BUILD_PATH 構(gòu)建目錄
CACHE 是否緩存
node {
    stage('Pre Git') {
        echo "${params.PROJECT_NAME},${params.PROJECT_VSERSION},${params.PROJECT_GIT_PATH}"
        dir("D:/jenkins/build") {
            if(fileExists("${params.PROJECT_NAME}")) {
                echo " git exit"
                dir("D:/jenkins/build/${params.PROJECT_NAME}") {
                    powershell " git fetch --all && git reset --hard origin/${params.BRANCH_NAME} && git pull"
                    powershell " git checkout ${params.BRANCH_NAME}"
                }
            } else {
                echo " git is not exit"
                powershell " git clone ${params.PROJECT_GIT_PATH}"
            }
        }
    }
    stage('Pre Env') {
        echo "check node_modules,${params.CACHE}"
        dir("D:/jenkins/build/${params.PROJECT_NAME}") { 
            if(!fileExists("node_modules")) {
                powershell "cnpm i"
            }
            if(!params.CACHE) {
                echo "CACHE --- ${params.CACHE}"
                powershell "rimraf node_modules"
                powershell "cnpm i"
            }
        }
    }
    stage('build') {
        echo "check node_modules"
        dir("D:/jenkins/build/${params.PROJECT_NAME}") { 
            bat "npm run build"
        }
    }
    stage('test') {
        echo "test case"
    }
    stage('deploy') {
        echo "deploy project"
        if(!fileExists("D:/jenkins/deploy/${params.PROJECT_NAME}")) { 
            powershell " mkdir D:/jenkins/deploy/${params.PROJECT_NAME}"
        }
        if(!fileExists("D:/jenkins/deploy/${params.PROJECT_NAME}/${params.PROJECT_VERSION}")) { 
            powershell " mkdir D:/jenkins/deploy/${params.PROJECT_NAME}/${params.PROJECT_VERSION}"
        }
        powershell "cp D:/jenkins/build/${params.PROJECT_NAME}/${params.BUILD_PATH}/* D:/jenkins/deploy/${params.PROJECT_NAME}/${params.PROJECT_VERSION} -Recurse"
    }
}

上述腳本創(chuàng)建了 5 個(gè) stage港粱,將構(gòu)建流程拆分為 5 個(gè)步驟:

  1. 拉取項(xiàng)目:判斷本地存不存在項(xiàng)目,存在就 pull 不存在直接 clone
  2. 安裝項(xiàng)目依賴:判斷項(xiàng)目依賴是否安裝完畢旦签,沒(méi)有安裝且強(qiáng)制清除緩存的情況下查坪,先安裝依賴
  3. 項(xiàng)目構(gòu)建:運(yùn)行項(xiàng)目構(gòu)建,此處后期可以把腳本抽出來(lái)
  4. 項(xiàng)目測(cè)試:預(yù)留宁炫,后面做項(xiàng)目流程卡點(diǎn)使用
  5. 項(xiàng)目發(fā)布:直接 cp 或者 ssh 上傳到你發(fā)布的地方即可(本地搭建了 Nginx 環(huán)境偿曙,所以復(fù)制到對(duì)應(yīng)的目錄即可)

當(dāng)然上述的腳本只完成了簡(jiǎn)單的構(gòu)建任務(wù),遇到復(fù)雜的系統(tǒng)會(huì)直接跪淋淀,簡(jiǎn)單列舉下大概率會(huì)遇到的問(wèn)題

  1. 多端構(gòu)建遥昧,比如一個(gè)項(xiàng)目需要直接構(gòu)建多端產(chǎn)物
  2. 區(qū)分開(kāi)發(fā)、測(cè)試朵纷、預(yù)發(fā)炭臭、線上等多環(huán)境
  3. 多命令構(gòu)建,復(fù)雜項(xiàng)目可能需要執(zhí)行多條命令袍辞,才能完成構(gòu)建產(chǎn)物
  4. 構(gòu)建產(chǎn)出目錄鞋仍,發(fā)布目錄等不確定性
  5. 等等…………………………

可以根據(jù)參數(shù)傳遞,多腳本等等配合解決上述問(wèn)題搅吁,具體要根據(jù)業(yè)務(wù)來(lái)設(shè)計(jì)

image

由于我是 windows 系統(tǒng)威创,所以文件處理比較坑爹落午,運(yùn)行速度慢而腳本還難寫(xiě),如果你想用的話肚豺,強(qiáng)烈建議上 linux溃斋。

上圖一共構(gòu)建 5 次,由于加了緩存判斷吸申,所以第一次構(gòu)建的時(shí)候梗劫,會(huì)去安裝對(duì)應(yīng)的依賴,耗時(shí)比較多截碴。

但是一般來(lái)說(shuō)梳侨,長(zhǎng)期迭代的項(xiàng)目,依賴變動(dòng)不會(huì)太頻繁日丹,所以只需要判斷是否安裝過(guò)依賴即可走哺,后續(xù)跳過(guò)依賴安裝,直接走構(gòu)建流程哲虾,節(jié)約倒杯水的時(shí)間丙躏。

看自己選擇,高興每次構(gòu)建全部重新安裝依賴也可以妒牙。做人嘛彼哼,開(kāi)心最重要

構(gòu)建產(chǎn)物演示

image

請(qǐng)注意上圖的鏈接有個(gè)版本號(hào)湘今,這個(gè)需要配合腳手架一起改造敢朱,在腳手架篇會(huì)具體介紹

Nginx

Nginx 是一款輕量級(jí)的 Web 服務(wù)器/反向代理服務(wù)器及電子郵件(IMAP/POP3)代理服務(wù)器,并在一個(gè) BSD-like 協(xié)議下發(fā)行摩瞎,可以在 UNIX拴签、GNU/Linux、BSD旗们、Mac OS X蚓哩、Solaris,以及 Microsoft Windows 等操作系統(tǒng)中運(yùn)行上渴。

在實(shí)際的運(yùn)作中岸梨,可以支持二萬(wàn)至四萬(wàn)并發(fā),性價(jià)比極高稠氮。沒(méi)錢(qián)就自己搭建曹阔,有錢(qián)直接上 cos, cdn隔披,買(mǎi)云服務(wù)它不香嗎赃份? PS:有錢(qián)真好

server {  #這里是我自己配置服務(wù)端口
    listen       10010;
    server_name resouce;
    root  D:/jenkins/deploy;  #訪問(wèn)文件根目錄
    autoindex on;  #是否瀏覽文件下的列表
    location / {  #是否允許跨域
        add_header Access-Control-Allow-Origin *;
    }
    add_header Cache-Control "no-cache,must-revalidate";# 是否緩存
}

根據(jù)上述配置,可以簡(jiǎn)單的配置一個(gè)靜態(tài)服務(wù)器抓韩。把前端項(xiàng)目丟進(jìn)去纠永,直接訪問(wèn)對(duì)應(yīng)的端口即可。

上述代碼谒拴,直接 copy 到 nginx.config 里面尝江,然后重啟即可

DevOps Jenkins Coding

封裝基礎(chǔ) Jenkins Api

項(xiàng)目選擇 jenkins 庫(kù)來(lái)拓展,注意如果你使用 TS 模式的話英上,需要安裝 @types/jenkins 依賴茂装。

import * as jenkins from "jenkins";

/**
 * Jenkins連接
 * @param type
 */
const getJenkins = function (
  type: "h5" | "node" | "nodeProduct" | "android" | "java"
) {
  const jenkinsConfig = {
    h5: {
      baseUrl: "http://devOps:118844ffb045d994acf8bb353e8d7b34f0@localhost:9001",
      crumbIssuer: true,
    },
    node: {
      baseUrl:
        "http://devOps:118844ffb045d994acf8bb353e8d7b34f0@localhost:9001",
      crumbIssuer: true,
    },
  };
  return jenkins(jenkinsConfig[type]);
};
/**
 * @description: 觸發(fā)jenkins流水線
 */
const buildJenkins = async ({ type, job, params }) => {
  const jenkinsCallback: any = await new Promise((resolve) => {
    getJenkins(type).job.build(
      { name: job, parameters: params },
      (err: any, data: any) => {
        if (err) {
          console.log("err: ", err);
          throw err;
        }
        resolve({ queueId: data });
      }
    );
  });
  return { data: jenkinsCallback };
};
/**
 * @description: 獲取當(dāng)前節(jié)點(diǎn)信息
 */
const getQueuedInfo = async ({ type, queueId }) => {
  const jenkinsCallback: any = await new Promise((resolve) => {
    getJenkins(type).queue.item(queueId, (err: any, data: any) => {
      if (err) {
        console.log("err---->", err);
        throw err;
      }
      resolve(data);
    });
  });
  return { data: jenkinsCallback };
};
/**
 * @description: 獲取當(dāng)前構(gòu)建信息
 */
const getJenkinsInfo = async ({ type, job, buildNumber }) => {
  console.log(type, job, buildNumber);
  const jenkinsCallback: any = await new Promise((resolve) => {
    getJenkins(type).build.get(job, buildNumber, (err: any, data: any) => {
      console.log("data: ", data);
      console.log("err: ", err);
      if (err) {
        console.log("err---->", err);
        throw err;
      }
      resolve(data);
    });
  });
  const { statusCode } = jenkinsCallback;
  if (jenkinsCallback && statusCode !== 404) {
    return { data: jenkinsCallback };
  } else {
    return { data: jenkinsCallback };
  }
};
/**
 * @description: 獲取jenkins console.log 信息
 */
const getJenkinsConsole = async ({ type, job, buildId }) => {
  const jenkinsCallback: any = await new Promise((resolve) => {
    getJenkins(type).build.log(job, buildId, (err: any, data: any) => {
      if (err) {
        return console.log("err---->", err);
      }
      resolve(data);
    });
  });
  return { data: jenkinsCallback };
};

export default {
  buildJenkins,
  getQueuedInfo,
  getJenkinsInfo,
  getJenkinsConsole,
};

上述是對(duì) Jenkins 的基本封裝,簡(jiǎn)單的封裝了一些我們需要用到的方法善延,具體的定制化,可以結(jié)合業(yè)務(wù)自己設(shè)計(jì)城侧。

各端的業(yè)務(wù)構(gòu)建易遣,可以選擇多個(gè) Jenkins 項(xiàng)目或者不同的 job 區(qū)分,不建議一個(gè) job 直接擼到黑嫌佑,這樣腳本會(huì)很復(fù)雜豆茫。

真的一個(gè) job 擼到黑的人,敬你是條漢子

image
// Controller
import { Post, Prefix, Get } from "egg-shell-decorators";
import BaseController from "./base";
@Prefix("build")
export default class BuildController extends BaseController {
  /**
   * @description: 創(chuàng)建構(gòu)建任務(wù)
   */
  @Post("/creatJob")
  public async getUserToken({
    request: {
      body: { params },
    },
  }) {
    const { ctx, app } = this;
    const { access_token: accessToken } = this.user;
    const {
      projectId,
      branchName,
      projectVersion,
      buildPath,
      type,
      cache,
    } = params;
    const project = await ctx.service.project.getProject({ projectId });
    let projectGitPath = project.projectUrl.replace(
      "http://",
      `https://oauth2:${accessToken}@`
    );
    const callBack = await ctx.service.build.buildProject({
      type,
      projectName: project.projectGitName,
      projectVersion,
      projectGitPath: `${projectGitPath}.git`,
      branchName,
      buildPath,
      cache,
    });
    this.success(callBack);
  }
}

// Service 
import { Service } from "egg";
export default class Build extends Service {
  /**
   * @description: 構(gòu)建項(xiàng)目
   */
  public async buildProject({
    type = "h5",
    projectName,
    projectVersion,
    projectGitPath,
    branchName,
    buildPath,
    cache,
  }) {
    const { ctx } = this;
    const callBack = await ctx.helper.api.jenkins.index.buildJenkins({
      type,
      job: "fe-base-h5",
      params: {
        PROJECT_NAME: projectName,
        PROJECT_VERSION: projectVersion,
        PROJECT_GIT_PATH: projectGitPath,
        BRANCH_NAME: branchName,
        BUILD_PATH: buildPath,
        CACHE: cache,
      },
    });
    return callBack;
  }
}

上述是業(yè)務(wù)代碼屋摇,一般獲取返回值的時(shí)候揩魂,存一下記錄 queueId, 通過(guò)調(diào)用 Jenkins api 獲取發(fā)布時(shí)間跟日志

image

如上圖炮温,將 Jenkins 與項(xiàng)目管理系統(tǒng)聯(lián)合起來(lái)火脉,方便用戶操作。

構(gòu)建信息推送

前端輪詢

直接用返回的 queueId 輪詢 Jenkins Api柒啤,可以直接獲取信息

優(yōu)點(diǎn):暴力倦挂、簡(jiǎn)單,開(kāi)發(fā)速度最快担巩,較為迅速

缺點(diǎn):用戶離開(kāi)頁(yè)面將無(wú)法感知方援,數(shù)據(jù)落庫(kù)會(huì)中斷,且極度消耗性能涛癌,多個(gè)用戶在操作同一個(gè)項(xiàng)目時(shí)犯戏,無(wú)法及時(shí)通知到位

后臺(tái)輪詢 + socket

Node 后臺(tái)通過(guò) queueId 直接輪詢 Jenkins Api,通過(guò) websocket 推送到前端展示

優(yōu)點(diǎn):暴力拳话,開(kāi)發(fā)速度先匪、難度適中,用戶即使離開(kāi)頁(yè)面假颇,數(shù)據(jù)依然能夠落庫(kù)胚鸯,可以同時(shí)推送到多個(gè)用戶

缺點(diǎn):Node 后臺(tái)性能消耗增加,需要前后臺(tái)一起配合開(kāi)發(fā)笨鸡,大量無(wú)用消息需要落庫(kù)姜钳,且節(jié)點(diǎn)無(wú)法感知

webhook + socket

Node 開(kāi)放 webhook 接口坦冠,Jenkins 流水線在每個(gè) stage 推送消息到 Node 后臺(tái),再通過(guò) socket 推送到前端展示

優(yōu)點(diǎn):最大程度節(jié)約資源哥桥,且可以自定義有效數(shù)據(jù)跟節(jié)點(diǎn)感知辙浑,時(shí)效性最高

缺點(diǎn):需要前端、node拟糕、腳本一起配合開(kāi)發(fā)判呕,成本較高

各位同學(xué)可以在實(shí)際開(kāi)發(fā)過(guò)程中結(jié)合業(yè)務(wù)選擇成本低,收益高的方式來(lái)配合開(kāi)發(fā)

最好的方式不一定是你最優(yōu)的選擇送滞,性價(jià)比最主要

建議

從第一篇看到目前這篇博客的同學(xué)侠草,如果團(tuán)隊(duì)缺少合適的項(xiàng)目管理或者想練習(xí) node 的情況下,可以上手試試看犁嗅,一般關(guān)鍵的代碼边涕,我有直接貼在博客上(大部分復(fù)制就能用啊)褂微。

構(gòu)建篇正式開(kāi)啟功蜓,后期會(huì)逐步推出構(gòu)建篇的博文,可能更偏向運(yùn)維開(kāi)發(fā)這塊宠蚂,前端同學(xué)如果吃力的情況下式撼,可以請(qǐng)教一下后端或者運(yùn)維同學(xué)。

不搶走所有人飯碗的前端不是一個(gè)好前端求厕,手動(dòng)狗頭

image

全系列博文目錄

后端模塊

  1. DevOps - Gitlab Api使用(已完成著隆,點(diǎn)擊跳轉(zhuǎn))
  2. DevOps - 搭建 DevOps 基礎(chǔ)平臺(tái) 基礎(chǔ)平臺(tái)搭建上篇 | 基礎(chǔ)平臺(tái)搭建中篇 | 基礎(chǔ)平臺(tái)搭建下篇
  3. DevOps - Gitlab CI 流水線構(gòu)建
  4. DevOps - Jenkins 流水線構(gòu)建
  5. DevOps - Docker 使用
  6. DevOps - 發(fā)布任務(wù)流程設(shè)計(jì)
  7. DevOps - 代碼審查卡點(diǎn)
  8. DevOps - Node 服務(wù)質(zhì)量監(jiān)控

前端模塊

  1. DevOps - H5 基礎(chǔ)腳手架
  2. DevOps - React 項(xiàng)目開(kāi)發(fā)

后期可能會(huì)根據(jù) DevOps 項(xiàng)目的實(shí)際開(kāi)發(fā)進(jìn)度對(duì)上述系列進(jìn)行調(diào)整

尾聲

此項(xiàng)目是從零開(kāi)發(fā),后續(xù)此系列博客會(huì)根據(jù)實(shí)際開(kāi)發(fā)進(jìn)度推出(真 TMD 累)甘改,項(xiàng)目完成之后旅东,會(huì)開(kāi)放部分源碼供各位同學(xué)參考。

為什么是開(kāi)放部分源碼十艾,因?yàn)橛行I(yè)務(wù)是需要貼合實(shí)際項(xiàng)目針對(duì)性開(kāi)發(fā)的抵代,開(kāi)放出去的公共模塊我寫(xiě)的認(rèn)真點(diǎn)

為了寫(xiě)個(gè)系列博客,居然真擼完整個(gè)系統(tǒng)(不是一般的累)忘嫉,覺(jué)得不錯(cuò)的同學(xué)麻煩順手三連(點(diǎn)贊荤牍,關(guān)注,轉(zhuǎn)發(fā))庆冕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末康吵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子访递,更是在濱河造成了極大的恐慌晦嵌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)王污,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)棒妨,“玉大人,你說(shuō)我怎么就攤上這事含长∪唬” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵拘泞,是天一觀的道長(zhǎng)纷纫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)陪腌,這世上最難降的妖魔是什么涛酗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮偷厦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘燕刻。我一直安慰自己只泼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布卵洗。 她就那樣靜靜地躺著请唱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪过蹂。 梳的紋絲不亂的頭發(fā)上十绑,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音酷勺,去河邊找鬼本橙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛脆诉,可吹牛的內(nèi)容都是我干的甚亭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼击胜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼亏狰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起偶摔,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤暇唾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體策州,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘸味,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抽活。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片硫戈。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖下硕,靈堂內(nèi)的尸體忽然破棺而出丁逝,到底是詐尸還是另有隱情,我是刑警寧澤梭姓,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布霜幼,位于F島的核電站,受9級(jí)特大地震影響誉尖,放射性物質(zhì)發(fā)生泄漏罪既。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一铡恕、第九天 我趴在偏房一處隱蔽的房頂上張望琢感。 院中可真熱鬧,春花似錦探熔、人聲如沸驹针。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)柬甥。三九已至,卻和暖如春其垄,著一層夾襖步出監(jiān)牢的瞬間苛蒲,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工绿满, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留臂外,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓喇颁,卻偏偏與公主長(zhǎng)得像寄月,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子无牵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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