《Go語(yǔ)言四十二章經(jīng)》第四十二章 WEB框架(Gin)

《Go語(yǔ)言四十二章經(jīng)》第四十二章 WEB框架(Gin)

作者:李驍

42.1 有關(guān)于Gin

Gin是Go語(yǔ)言寫(xiě)的一個(gè)web框架,API性能超強(qiáng)卿操,運(yùn)行速度號(hào)稱(chēng)較httprouter要快40x警检。開(kāi)源網(wǎng)址:https://github.com/gin-gonic/gin

下載安裝gin包:

go get -u github.com/gin-gonic/gin

一個(gè)簡(jiǎn)單的例子:

package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong", 
        })
    })
    r.Run() // listen and serve on 0.0.0.0:8080
}

編譯運(yùn)行程序,打開(kāi)瀏覽器害淤,訪(fǎng)問(wèn) http://localhost:8080/ping
頁(yè)面顯示:

{"message":"pong"}

以Json格式輸出了數(shù)據(jù)扇雕。

gin的功能不只是簡(jiǎn)單輸出Json數(shù)據(jù)。它是一個(gè)輕量級(jí)的WEB框架筝家,支持RESTful風(fēng)格API洼裤,支持GET,POST溪王,PUT腮鞍,PATCH,DELETE莹菱,OPTIONS 等http方法移国,支持文件上傳,分組路由道伟,Multipart/Urlencoded FORM迹缀,以及支持JsonP,參數(shù)處理等等功能蜜徽,這些都和WEB緊密相關(guān)祝懂,通過(guò)提供這些功能,使開(kāi)發(fā)人員更方便地處理WEB業(yè)務(wù)拘鞋。

42.2 Gin實(shí)際應(yīng)用

接下來(lái)使用Gin作為框架來(lái)搭建一個(gè)擁有靜態(tài)資源站點(diǎn)砚蓬,動(dòng)態(tài)WEB站點(diǎn),以及RESTFull API接口站點(diǎn)(可專(zhuān)門(mén)作為手機(jī)APP應(yīng)用提供服務(wù)使用)組成的盆色,亦可根據(jù)情況分拆這套系統(tǒng)灰蛙,每種功能獨(dú)立出來(lái)單獨(dú)提供服務(wù)。

下面按照一套系統(tǒng)但采用分站點(diǎn)來(lái)說(shuō)明隔躲,首先是整個(gè)系統(tǒng)的目錄結(jié)構(gòu)摩梧,website目錄下面static是資源類(lèi)文件,為靜態(tài)資源站點(diǎn)專(zhuān)用宣旱;photo目錄是UGC上傳圖片目錄仅父,tpl是動(dòng)態(tài)站點(diǎn)的模板。當(dāng)然這個(gè)目錄結(jié)構(gòu)是一種約定,你可以根據(jù)情況來(lái)修改驾霜。整個(gè)項(xiàng)目已經(jīng)開(kāi)源案训,你可以訪(fǎng)問(wèn)來(lái)詳細(xì)了解:https://github.com/ffhelicopter/tmm

具體每個(gè)站點(diǎn)的功能怎么實(shí)現(xiàn)呢?請(qǐng)看下面有關(guān)每個(gè)功能的講述:

一:靜態(tài)資源站點(diǎn)

一般網(wǎng)站開(kāi)發(fā)中粪糙,我們會(huì)考慮把js强霎,css,以及資源圖片放在一起蓉冈,作為靜態(tài)站點(diǎn)部署在CDN城舞,提升響應(yīng)速度。采用Gin實(shí)現(xiàn)起來(lái)非常簡(jiǎn)單寞酿,當(dāng)然也可以使用net/http包輕松實(shí)現(xiàn)家夺,但使用Gin會(huì)更方便。

不管怎么樣伐弹,使用Go開(kāi)發(fā)拉馋,我們可以不用花太多時(shí)間在WEB服務(wù)環(huán)境搭建上,程序啟動(dòng)就直接可以提供WEB服務(wù)了惨好。

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    // 靜態(tài)資源加載煌茴,本例為css,js以及資源圖片
    router.StaticFS("/public", http.Dir("D:/goproject/src/github.com/ffhelicopter/tmm/website/static"))
    router.StaticFile("/favicon.ico", "./resources/favicon.ico")

    // Listen and serve on 0.0.0.0:80
    router.Run(":80")
}

首先需要是生成一個(gè)Engine ,這是gin的核心日川,默認(rèn)帶有Logger 和 Recovery 兩個(gè)中間件蔓腐。

router := gin.Default()

StaticFile 是加載單個(gè)文件,而StaticFS 是加載一個(gè)完整的目錄資源:

func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes

這些目錄下資源是可以隨時(shí)更新龄句,而不用重新啟動(dòng)程序』芈郏現(xiàn)在編譯運(yùn)行程序,靜態(tài)站點(diǎn)就可以正常訪(fǎng)問(wèn)了分歇。

訪(fǎng)問(wèn)http://localhost/public/images/logo.jpg 圖片加載正常傀蓉。每次請(qǐng)求響應(yīng)都會(huì)在服務(wù)端有日志產(chǎn)生,包括響應(yīng)時(shí)間职抡,加載資源名稱(chēng)僚害,響應(yīng)狀態(tài)值等等。

二:動(dòng)態(tài)站點(diǎn)

如果需要?jiǎng)討B(tài)交互的功能繁调,比如發(fā)一段文字+圖片上傳。由于這些功能出來(lái)前端頁(yè)面外靶草,還需要服務(wù)端程序一起來(lái)實(shí)現(xiàn)蹄胰,而且迭代需要經(jīng)常需要修改代碼和模板,所以把這些統(tǒng)一放在一個(gè)大目錄下奕翔,姑且稱(chēng)動(dòng)態(tài)站點(diǎn)裕寨。

tpl是動(dòng)態(tài)站點(diǎn)所有模板的根目錄,這些模板可調(diào)用靜態(tài)資源站點(diǎn)的css,圖片等宾袜;photo是圖片上傳后存放的目錄捻艳。

package main

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "time"

    "github.com/ffhelicopter/tmm/handler"

    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    // 靜態(tài)資源加載,本例為css,js以及資源圖片
    router.StaticFS("/public", http.Dir("D:/goproject/src/github.com/ffhelicopter/tmm/website/static"))
    router.StaticFile("/favicon.ico", "./resources/favicon.ico")

    // 導(dǎo)入所有模板庆猫,多級(jí)目錄結(jié)構(gòu)需要這樣寫(xiě)
    router.LoadHTMLGlob("website/tpl/*/*")

    // website分組
    v := router.Group("/")
    {

        v.GET("/index.html", handler.IndexHandler)
        v.GET("/add.html", handler.AddHandler)
        v.POST("/postme.html", handler.PostmeHandler)
    }

    // router.Run(":80") 
    // 這樣寫(xiě)就可以了认轨,下面所有代碼(go1.8+)是為了優(yōu)雅處理重啟等動(dòng)作。
    srv := &http.Server{
        Addr:         ":80",
        Handler:      router,
        ReadTimeout:  30 * time.Second,
        WriteTimeout: 30 * time.Second,
    }

    go func() {
        // 監(jiān)聽(tīng)請(qǐng)求
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()

    // 優(yōu)雅Shutdown(或重啟)服務(wù)
    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt) // syscall.SIGKILL
    <-quit
    log.Println("Shutdown Server ...")

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("Server Shutdown:", err)
    }
    select {
    case <-ctx.Done():
    }   
    log.Println("Server exiting")
}

在動(dòng)態(tài)站點(diǎn)實(shí)現(xiàn)中月培,引入WEB分組以及優(yōu)雅重啟這兩個(gè)功能嘁字。WEB分組功能可以通過(guò)不同的入口根路徑來(lái)區(qū)別不同的模塊,這里我們可以訪(fǎng)問(wèn):http://localhost/index.html 杉畜。如果新增一個(gè)分組纪蜒,比如:

v := router.Group("/login") 

我們可以訪(fǎng)問(wèn):http://localhost/login/xxxx,xxx是我們?cè)趘.GET方法或v.POST方法中的路徑此叠。

    // 導(dǎo)入所有模板纯续,多級(jí)目錄結(jié)構(gòu)需要這樣寫(xiě)
    router.LoadHTMLGlob("website/tpl/*/*")
    
    // website分組
    v := router.Group("/")
    {

        v.GET("/index.html", handler.IndexHandler)
        v.GET("/add.html", handler.AddHandler)
        v.POST("/postme.html", handler.PostmeHandler)
    }

通過(guò)router.LoadHTMLGlob("website/tpl//") 導(dǎo)入模板根目錄下所有的文件。在前面有講過(guò)html/template 包的使用灭袁,這里模板文件中的語(yǔ)法和前面一致猬错。

    router.LoadHTMLGlob("website/tpl/*/*")

比如v.GET("/index.html", handler.IndexHandler) ,通過(guò)訪(fǎng)問(wèn)http://localhost/index.html 這個(gè)URL简卧,實(shí)際由handler.IndexHandler來(lái)處理兔魂。而在tmm目錄下的handler存放了package handler 文件。在包里定義了IndexHandler函數(shù)举娩,它使用了index.html模板析校。

func IndexHandler(c *gin.Context) {
    c.HTML(http.StatusOK, "index.html", gin.H{
        "Title": "作品欣賞",
    })
}

index.html模板:

<!DOCTYPE html>
<html>
<head>
{{template "header" .}}
</head>
<body>

<!--導(dǎo)航-->
<div class="feeds">
    <div class="top-nav">
        <a href="/index.tml" class="active">欣賞</a>
        <a href="/add.html" class="add-btn">
            <svg class="icon" aria-hidden="true">
                <use  xlink:href="#icon-add"></use>
            </svg>
            發(fā)布
        </a>
    </div>
    <input type="hidden" id="showmore" value="{$showmore}">
    <input type="hidden" id="page" value="{$page}">
    <!--</div>-->
</div>
<script type="text/javascript">
    var done = true;
    $(window).scroll(function(){
        var scrollTop = $(window).scrollTop();
        var scrollHeight = $(document).height();
        var windowHeight = $(window).height();
        var showmore = $("#showmore").val();
        if(scrollTop + windowHeight + 300 >= scrollHeight && showmore == 1 && done){
            var page = $("#page").val();
            done = false;
            $.get("{:U('Product/listsAjax')}", { page : page }, function(json) {
                if (json.rs != "") {
                    $(".feeds").append(json.rs);
                    $("#showmore").val(json.showmore);
                    $("#page").val(json.page);
                    done = true;
                }
            },'json');
        }
    });
</script>
    <script src="http://at.alicdn.com/t/font_ttszo9rnm0wwmi.js"></script>
</body>
</html>

在index.html模板中,通過(guò){{template "header" .}}語(yǔ)句铜涉,嵌套了header.html模板智玻。

header.html模板:

{{ define "header" }}
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="format-detection" content="telephone=no,email=no">
    <title>{{ .Title }}</title>
    <link rel="stylesheet" href="/public/css/common.css">
    <script src="/public/lib/jquery-3.1.1.min.js"></script>
    <script src="/public/lib/jquery.cookie.js"></script>
    <link href="/public/css/font-awesome.css?v=4.4.0" rel="stylesheet">
{{ end }}

{{ define "header" }} 讓我們?cè)谀0迩短讜r(shí)直接使用header名字,而在index.html中的{{template "header" .}} 注意“.”芙代,可以使參數(shù)嵌套傳遞吊奢,否則不能傳遞,比如這里的Title纹烹。

現(xiàn)在我們?cè)L問(wèn) http://localhost/index.html 页滚,可以看到瀏覽器顯示Title 是“作品欣賞”,這個(gè)Title是通過(guò)IndexHandler來(lái)指定的铺呵。

接下來(lái)點(diǎn)擊“發(fā)布”按鈕裹驰,我們進(jìn)入發(fā)布頁(yè)面,上傳圖片片挂,點(diǎn)擊“完成”提交幻林,會(huì)提示我們成功上傳圖片贞盯。可以在photo目錄中看到剛才上傳的圖片沪饺。

注意:
由于在本人在發(fā)布到github的代碼中躏敢,在處理圖片上傳的代碼中,除了服務(wù)器存儲(chǔ)外整葡,還實(shí)現(xiàn)了IPFS發(fā)布存儲(chǔ)件余,如果不需要IPFS,請(qǐng)注釋相關(guān)代碼掘宪。

有關(guān)IPFS:
IPFS本質(zhì)上是一種內(nèi)容可尋址蛾扇、版本化、點(diǎn)對(duì)點(diǎn)超媒體的分布式存儲(chǔ)魏滚、傳輸協(xié)議镀首,目標(biāo)是補(bǔ)充甚至取代過(guò)去20年里使用的超文本媒體傳輸協(xié)議(HTTP),希望構(gòu)建更快鼠次、更安全更哄、更自由的互聯(lián)網(wǎng)時(shí)代。

IPFS 不算嚴(yán)格意義上區(qū)塊鏈項(xiàng)目腥寇,是一個(gè)去中心化存儲(chǔ)解決方案成翩,但有些區(qū)塊鏈項(xiàng)目通過(guò)它來(lái)做存儲(chǔ)。

IPFS項(xiàng)目有在github上開(kāi)源赦役,Go語(yǔ)言實(shí)現(xiàn)哦麻敌,可以關(guān)注并了解。

優(yōu)雅重啟在迭代中有較好的實(shí)際意義掂摔,每次版本發(fā)布术羔,如果直接停服務(wù)在部署重啟,對(duì)業(yè)務(wù)還是有蠻大的影響乙漓,而通過(guò)優(yōu)雅重啟级历,這方面的體驗(yàn)可以做得更好些。這里ctrl + c 后過(guò)5秒服務(wù)停止叭披。

三:中間件的使用寥殖,在API中可能使用限流,身份驗(yàn)證等

Go 語(yǔ)言中net/http設(shè)計(jì)的一大特點(diǎn)就是特別容易構(gòu)建中間件涩蜘。 gin也提供了類(lèi)似的中間件嚼贡。需要注意的是在gin里面中間件只對(duì)注冊(cè)過(guò)的路由函數(shù)起作用。

而對(duì)于分組路由同诫,嵌套使用中間件茄厘,可以限定中間件的作用范圍彤路。大致分為全局中間件压怠,單個(gè)路由中間件和分組中間件躯保。

即使是全局中間件,其使用前的代碼不受影響贩猎。 也可在handler中局部使用熊户,具體見(jiàn)api.GetUser 。

在高并發(fā)場(chǎng)景中吭服,有時(shí)候需要用到限流降速的功能嚷堡,這里引入一個(gè)限流中間件。有關(guān)限流方法常見(jiàn)有兩種艇棕,具體可自行研究蝌戒,這里只講使用。

導(dǎo)入 import "github.com/didip/tollbooth/limiter" 包沼琉,在上面代碼基礎(chǔ)上增加如下語(yǔ)句:

    //rate-limit 限流中間件 
    lmt := tollbooth.NewLimiter(1, nil)
    lmt.SetMessage("服務(wù)繁忙北苟,請(qǐng)稍后再試...")

并修改

v.GET("/index.html", LimitHandler(lmt), handler.IndexHandler) 

當(dāng)F5刷新刷新http://localhost/index.html 頁(yè)面時(shí),瀏覽器會(huì)顯示:服務(wù)繁忙打瘪,請(qǐng)稍后再試...

限流策略也可以為IP:

tollbooth.LimitByKeys(lmt, []string{"127.0.0.1", "/"})

更多限流策略的配置友鼻,可以進(jìn)一步github.com/didip/tollbooth/limiter 了解。

四:RestFull API接口

前面說(shuō)了在gin里面可以采用分組來(lái)組織訪(fǎng)問(wèn)URL闺骚,這里RestFull API需要給出不同的訪(fǎng)問(wèn)URL來(lái)和動(dòng)態(tài)站點(diǎn)區(qū)分彩扔,所以新建了一個(gè)分組v1。

在瀏覽器中訪(fǎng)問(wèn)http://localhost/v1/user/1100000/

這里對(duì)v1.GET("/user/:id/*action", LimitHandler(lmt), api.GetUser) 進(jìn)行了限流控制僻爽,所以如果頻繁訪(fǎng)問(wèn)上面地址也將會(huì)有限制虫碉,這在API接口中非常有作用。

通過(guò) api這個(gè)包胸梆,來(lái)實(shí)現(xiàn)所有有關(guān)API的代碼敦捧。在GetUser函數(shù)中,通過(guò)讀取mysql數(shù)據(jù)庫(kù)乳绕,查找到對(duì)應(yīng)userid的用戶(hù)信息绞惦,并通過(guò)Json格式返回給client。

在api.GetUser中洋措,設(shè)置了一個(gè)局部中間件:

    //CORS 局部CORS济蝉,可在路由中設(shè)置全局的CORS
    c.Writer.Header().Add("Access-Control-Allow-Origin", "*")

gin關(guān)于參數(shù)的處理,api包中api.go文件中有簡(jiǎn)單說(shuō)明菠发,限于篇幅原因王滤,就不在此展開(kāi)。這個(gè)項(xiàng)目的詳細(xì)情況滓鸠,請(qǐng)?jiān)L問(wèn) https://github.com/ffhelicopter/tmm 了解雁乡。有關(guān)gin的更多信息,請(qǐng)?jiān)L問(wèn)https://github.com/gin-gonic/gin糜俗,該開(kāi)源項(xiàng)目比較活躍踱稍,可以關(guān)注曲饱。

完整main.go代碼:

package main

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "time"

    "github.com/didip/tollbooth"
    "github.com/didip/tollbooth/limiter"
    "github.com/ffhelicopter/tmm/api"
    "github.com/ffhelicopter/tmm/handler"

    "github.com/gin-gonic/gin"
)

// 定義全局的CORS中間件
func Cors() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
        c.Next()
    }
}

func LimitHandler(lmt *limiter.Limiter) gin.HandlerFunc {
    return func(c *gin.Context) {
        httpError := tollbooth.LimitByRequest(lmt, c.Writer, c.Request)
        if httpError != nil {
            c.Data(httpError.StatusCode, lmt.GetMessageContentType(), []byte(httpError.Message))
            c.Abort()
        } else {
            c.Next()
        }
    }
}

func main() {
gin.SetMode(gin.ReleaseMode)
    router := gin.Default()

    // 靜態(tài)資源加載,本例為css,js以及資源圖片
    router.StaticFS("/public", http.Dir("D:/goproject/src/github.com/ffhelicopter/tmm/website/static"))
    router.StaticFile("/favicon.ico", "./resources/favicon.ico")

    // 導(dǎo)入所有模板珠月,多級(jí)目錄結(jié)構(gòu)需要這樣寫(xiě)
    router.LoadHTMLGlob("website/tpl/*/*")
    // 也可以根據(jù)handler扩淀,實(shí)時(shí)導(dǎo)入模板。

    // website分組
    v := router.Group("/")
    {

        v.GET("/index.html", handler.IndexHandler)
        v.GET("/add.html", handler.AddHandler)
        v.POST("/postme.html", handler.PostmeHandler)
    }

    // 中間件 golang的net/http設(shè)計(jì)的一大特點(diǎn)就是特別容易構(gòu)建中間件啤挎。
    // gin也提供了類(lèi)似的中間件驻谆。需要注意的是中間件只對(duì)注冊(cè)過(guò)的路由函數(shù)起作用。
    // 對(duì)于分組路由庆聘,嵌套使用中間件胜臊,可以限定中間件的作用范圍。
    // 大致分為全局中間件伙判,單個(gè)路由中間件和群組中間件象对。

    // 使用全局CORS中間件。
    // router.Use(Cors())
    // 即使是全局中間件澳腹,在use前的代碼不受影響
    // 也可在handler中局部使用织盼,見(jiàn)api.GetUser

    //rate-limit 中間件
    lmt := tollbooth.NewLimiter(1, nil)
    lmt.SetMessage("服務(wù)繁忙,請(qǐng)稍后再試...")

    // API分組(RESTFULL)以及版本控制
    v1 := router.Group("/v1")
    {
        // 下面是群組中間的用法
        // v1.Use(Cors())

        // 單個(gè)中間件的用法
        // v1.GET("/user/:id/*action",Cors(), api.GetUser)

        // rate-limit
        v1.GET("/user/:id/*action", LimitHandler(lmt), api.GetUser)

        //v1.GET("/user/:id/*action", Cors(), api.GetUser)
        // AJAX OPTIONS 酱塔,下面是有關(guān)OPTIONS用法的示例
        // v1.OPTIONS("/users", OptionsUser)      // POST
        // v1.OPTIONS("/users/:id", OptionsUser)  // PUT, DELETE
    }

    srv := &http.Server{
        Addr:         ":80",
        Handler:      router,
        ReadTimeout:  30 * time.Second,
        WriteTimeout: 30 * time.Second,
    }

    go func() {
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()

    // 優(yōu)雅Shutdown(或重啟)服務(wù)
    // 5秒后優(yōu)雅Shutdown服務(wù)
    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt) //syscall.SIGKILL
    <-quit
    log.Println("Shutdown Server ...")

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("Server Shutdown:", err)
    }
    select {
    case <-ctx.Done():
    }
    log.Println("Server exiting")
}

本書(shū)《Go語(yǔ)言四十二章經(jīng)》內(nèi)容在github上同步地址:https://github.com/ffhelicopter/Go42
本書(shū)《Go語(yǔ)言四十二章經(jīng)》內(nèi)容在簡(jiǎn)書(shū)同步地址: http://www.reibang.com/nb/29056963

雖然本書(shū)中例子都經(jīng)過(guò)實(shí)際運(yùn)行沥邻,但難免出現(xiàn)錯(cuò)誤和不足之處,煩請(qǐng)您指出羊娃;如有建議也歡迎交流唐全。
聯(lián)系郵箱:roteman@163.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蕊玷,隨后出現(xiàn)的幾起案子邮利,更是在濱河造成了極大的恐慌,老刑警劉巖垃帅,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件延届,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贸诚,警方通過(guò)查閱死者的電腦和手機(jī)方庭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酱固,“玉大人械念,你說(shuō)我怎么就攤上這事≡吮” “怎么了龄减?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)班眯。 經(jīng)常有香客問(wèn)我希停,道長(zhǎng)烁巫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任宠能,我火速辦了婚禮程拭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棍潘。我一直安慰自己,他們只是感情好崖媚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布亦歉。 她就那樣靜靜地躺著,像睡著了一般畅哑。 火紅的嫁衣襯著肌膚如雪肴楷。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天荠呐,我揣著相機(jī)與錄音赛蔫,去河邊找鬼。 笑死泥张,一個(gè)胖子當(dāng)著我的面吹牛呵恢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播媚创,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼渗钉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了钞钙?” 一聲冷哼從身側(cè)響起鳄橘,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芒炼,沒(méi)想到半個(gè)月后瘫怜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡本刽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年鲸湃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盅安。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唤锉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出别瞭,到底是詐尸還是另有隱情窿祥,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布蝙寨,位于F島的核電站晒衩,受9級(jí)特大地震影響嗤瞎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜听系,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一贝奇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧靠胜,春花似錦掉瞳、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至址愿,卻和暖如春该镣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背响谓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工损合, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娘纷。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓嫁审,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赖晶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子土居,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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