Koa 學(xué)習(xí)總結(jié)

前言

Koa是基于Node.js的下一代web框架悼沈,由Express團隊打造,特點:優(yōu)雅姐扮、簡潔絮供、靈活、體積小茶敏。幾乎所有功能都需要通過中間件實現(xiàn)壤靶。

準(zhǔn)備

  1. 檢查Node版本,至少在7.6.0以上惊搏,因為Koa采用很多Es7的語法贮乳,比如async/await,
  2. 創(chuàng)建項目恬惯、安裝依賴
mkdir study_koa

cd study_koa

npm init -y

npm install koa

一向拆、基本用法

  1. 創(chuàng)建一個應(yīng)用程序 新建app.js
const Koa = require('koa');

const app = new Koa();

app.use(async ctx => {
    // ctx.body 即服務(wù)端響應(yīng)的數(shù)據(jù)
    ctx.body = 'Hello Koa';
})

// 監(jiān)聽端口、啟動程序
app.listen(3000, err => {
    if (err) throw err;
    console.log('runing...');
})
  1. 啟動
node app.js
  1. 訪問 127.0.0.1:3000 會看到頁面顯示Hello Koa

即便沒有給ctx.body 設(shè)置響應(yīng)數(shù)據(jù)酪耳,或訪問不存在的路由浓恳,頁面也會顯示Not Found,這是koa底層做了處理,不像原生Node或Express一樣頁面會一直處于響應(yīng)狀態(tài)颈将。

二梢夯、Context

Koa將Node的request 和 response對象都封裝到了context中,每次請求都會創(chuàng)建一個ctx晴圾,并且在中間件中作為接收器使用颂砸。

以下是剛才訪問時的ctx對象

let ctx = {
    // 請求
    request: {
        method: 'GET',
        url: '/',
        // request header
        header: {
            host: '127.0.0.1:3030',
            connection: 'keep-alive',
            'cache-control': 'max-age=0',
            'upgrade-insecure-requests': '1',
            'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36',
            accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'accept-encoding': 'gzip, deflate, br',
            'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
            cookie: 'connect.sid=s%3AnQtQApNcQ55RmpjnkmQvWNTrdjYhZnlh.1FQUbVqpwpdRj8N6wjv8nOarf8hyzIpcxXN2LPYXGy0'
        }
    },
    // 響應(yīng)
    response: {
         status: 200, 
         message: 'ok', 
         header: { 
            'content-type': 'text/plain; charset=utf-8',
            'content-length': '9'
        }
    },
    app: { 
        subdomainOffset: 2, 
        proxy: false, 
        env: 'development' 
    },
    originalUrl: '/',
    // 原生Node的request對象
    req: '<original node req>',
    // 原生Node的reponse對象
    res: '<original node res>',
    socket: '<original node socket>'
}
剖析ctx
  1. 區(qū)分request、response死姚、req沾凄、res
  • requset    ctx的請求對象
  • response    ctx的響應(yīng)對象
  • req      Node的請求對象
  • res      Node的響應(yīng)對象
注意:繞過Koa的response是不被處理的,避免使用Node的屬性和方法知允,比如:
res.statusCode
res.writeHead()
res.write()
res.end()

即便使用ctx.res.write()也不會得到預(yù)期結(jié)果,比如:ctx.res.write('hello')叙谨,結(jié)果是hellook温鸽,會把message的值拼接上。

  1. ctx.state
    推薦的命名空間手负,用于通過中間件傳遞信息到你的前端視圖涤垫。比如每個頁面都要用到用戶信息,那就可以掛載在ctx.state竟终。類似于添加全局屬性蝠猬。
ctx.state.userInfo = {
    name: 'Jack',
    age: 18
}
  1. ctx.app
    應(yīng)用程序?qū)嵗?/li>

有關(guān)cookie和session單獨介紹用法。

三统捶、路由

Koa中的路由和Express不同榆芦,Express是把路由集成在Express中,Koa則需要通過kao-router模塊使用喘鸟。

  1. 安裝:
npm i koa-router
  1. 使用
const Koa = require('koa');
// 直接調(diào)用的方式
const router = require('koa-router')();
// 或 單獨創(chuàng)建router的實例
const Router = require('koa-router');
const router = new Router();

router.get('/', async ctx => {
    ctx.body = 'Hello Router';
})

// 啟動路由
app.use(router.routes()).use(router.allowedMethods())
// 以上為官方推薦方式匆绣,allowedMethods用在routes之后,作用是根據(jù)ctx.status設(shè)置response header.

app.listen(3000, err => {
    if (err) throw err;
    console.log('runing...');
});

四什黑、中間件

Koa最大的特色和最優(yōu)的設(shè)計就是中間件崎淳,就是在匹配路由之前和匹配路由之后執(zhí)行函數(shù)。
使用app.use()加載中間件愕把。每個中間件接收兩個參數(shù)拣凹,ctx對象和next函數(shù),通過調(diào)用next將執(zhí)行權(quán)交給下一個中間件恨豁。

中間件分為:

  • 應(yīng)用級中間件
  • 路由級中間件
  • 錯誤處理中間件
  • 第三方中間件
  1. 應(yīng)用級中間件
const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

// 應(yīng)用級中間件
app.use(async (ctx, next) => {
    await next();
})

router.get('/', async ctx => {
    ctx.body = 'hello koa';
})

// 啟動路由
app.use(router.routes()).use(router.allowedMethods());

app.listen(3000, err => {
    if (err) throw err;
    console.log('runing...')
})

任何路由都會先經(jīng)過應(yīng)用級中間件嚣镜,當(dāng)執(zhí)行完成next后再去匹配相應(yīng)的路由。

  1. 路由中間件
router.get('/user', async (ctx, next) => {
    console.log(111)
    await next();
})

router.get('/user', async (ctx, next) => {
    console.log(222)
    await next();
})

router.get('/user', async ctx => {
    console.log(333)
    ctx.body = 'Hello'
})  

// 依次打印
111
222
333

路由匹配過程中圣絮,對于相同路由會從上往下依次執(zhí)行中間件淑履,直到最后一個沒有next參數(shù)的中間件為止。

  1. 錯誤處理中間件
app.use(async (ctx, next)=> {
    await next();
    if(ctx.status === 404){
        ctx.body="404頁面"
    }
});

路由在匹配成功并執(zhí)行完相應(yīng)的操作后還會再次進(jìn)入應(yīng)用級中間件執(zhí)行 next 之后的邏輯撵枢。所以對于404、500等錯誤可以在最外層的(第一個)應(yīng)用級中間件的next之后做相應(yīng)的處理凡涩。
如果只有一個應(yīng)用級中間件的話,順序就無所謂所有路由中間件之前和之后了疹蛉。

  1. 第三方中間件
    類似于koa-router活箕、koa-bodyparser等就是第三方中間件。

  2. 中間件的合成
    koa-compose 模塊可以將多個中間件合成為一個可款。

const compose = require('koa-compose')
const first = asycn (ctx, next) => {
    await next();
}
const second = async ctx => {
    ctx.body = 'Hello';
}

const middle = compose([first, second]);
app.use(middle);
  1. 中間件的執(zhí)行順序
    多個中間件會形成堆棧結(jié)構(gòu)育韩,按先進(jìn)后出順序執(zhí)行
app.use(async (ctx, next) => {
    console.log('1中間件第1次執(zhí)行')
    await next();
    console.log('7中間件第7次執(zhí)行')
})

app.use(async (ctx, next) => {
    console.log('2中間件第2次執(zhí)行');
    await next();
    console.log('6中間件第6次執(zhí)行')
})

router.get('/user', async (ctx, next) => {
    console.log('3中間件第3次執(zhí)行')
    await next()
    console.log('5中間件第5次執(zhí)行')
})

router.get('/user', (ctx, next) => {
    console.log('4中間件第4次執(zhí)行')
    ctx.body = 'Hello Koa';
})
// 1中間件第1次執(zhí)行
// 2中間件第2次執(zhí)行
// 3中間件第3次執(zhí)行
// 4中間件第4次執(zhí)行
// 5中間件第5次執(zhí)行
// 6中間件第6次執(zhí)行
// 7中間件第7次執(zhí)行

由此可以看出中間件的執(zhí)行順序是先進(jìn)后出的方式。類似于洋蔥圖闺鲸。

洋蔥圖

五筋讨、獲取請求數(shù)據(jù)

  1. GET 傳值
  • Koa 中 GET傳值通過request接收,有兩種方式: query 和 querystring

    query:返回的是參數(shù)對象摸恍。 {name: 'jack', age: 12}
    querystring:返回的是請求字符串悉罕。 name=jack&age=12

  • query和querystring可以從request中獲取,也可以直接從ctx中獲取立镶。

let request = ctx.request;
let query = request.query;
let querystring = request.querystring;

// 直接ctx獲取
ctx.query
ctx.querystring
  1. POST 傳值
    通過post傳遞的值我們可以通過原生Node封裝壁袄,也可以通過第三方模塊接收。
  • 自定義封裝
const querystring = require('querystring');

module.exports = ctx => {
    return new Promise((resolve, reject) => {
        try {
            let data = '';

            // ctx.req實際上就是原生node中的req
            ctx.req.on('data', (chunk) => {
                data += chunk;
            })

            ctx.req.on('end', () => {
                data = querystring.parse(data);
                resolve(data);
            })
        } 
        catch(err) {
            reject(err);
        }
    })
}
  • 使用koa-bodyparser模塊
const bodyParser = require('koa-bodyparser');
app.use(bodyParser());

// 獲取
ctx.request.body

六媚媒、處理靜態(tài)資源

對于諸如js嗜逻、css、img等靜態(tài)資源采用koa-static中間件處理缭召。

npm i koa-static
配置:

比如靜態(tài)目錄為static:

// 靜態(tài)資源配置
// app.use(require('koa-static')('static'))

// or
// app.use(require('koa-static')('./static'))

// or
// app.use(require('koa-static')(__dirname + '/static'))

// or 使用path.join() 的時候栈顷,static前面的/可加可不加,該方法會內(nèi)部會做處理
app.use(require('koa-static')(path.join(__dirname, 'static')));

在模板中即可訪問:

<link rel="stylesheet" href="/css/header.css">
<img src="/image/account.eb695dc.png"/>

七嵌巷、模板引擎

koa生態(tài)的模板引擎挺多的妨蛹,比如ejs、art-template等晴竞。

1. koa-ejs
npm i koa-ejs
const render = require('koa-ejs');
  • 配置
render(app, {
    // views 視圖根目錄
    root: path.join(__dirname, 'views'),
    layout: 'template',     // 公用文件 若要禁用蛙卤,設(shè)置為false即可
    viewExt: 'html',        // 擴展名
    cache: false,           // 緩存 default true
    debug: false            // 如果開啟debug模式,則會在終端實時打印信息 default false
});
  • 使用
/**
 * 參數(shù)1: 模板名
 * 參數(shù)2: 數(shù)據(jù)(可選)
 */
await ctx.render(templateName, data);
2. art-template
npm install --save art-template
npm install --save koa-art-template
  • 配置
const render = require('koa-art-template');

// 配置模板引擎
render(app, {
    root: path.join(__dirname, 'views'), // 視圖目錄
    extname: '.html',
    debug: process.env.NODE_ENV !== 'production'
});

使用方式和ejs一樣噩死。

性能上相比颤难,art-template比ejs快很多,開發(fā)中用的最多的還是art-template已维。

八行嗤、cookie 和 session

http是無狀態(tài)、無連接的垛耳。不會對之前發(fā)生過的請求和相應(yīng)狀態(tài)進(jìn)行管理栅屏。也就是說飘千,無法根據(jù)之前的狀態(tài)進(jìn)行本次的請求處理。

比如訪問淘寶首頁并登錄賬號后栈雳,當(dāng)再打開淘寶其他頁面時护奈,因為每一次的訪問都是獨立的,服務(wù)器并不知道你已經(jīng)登錄哥纫,所以還是不能下單或者加購物車之類的操作霉旗。

cookie
  1. cookie簡單介紹

cookie是客戶端第一次訪問服務(wù)器的時候,服務(wù)器在下行HTTP報文時通過響應(yīng)頭的set-cookie字段給瀏覽器分配的一個具有特殊標(biāo)識的文本信息蛀骇,此后當(dāng)客戶端再次訪問同一域名時厌秒,便會將該字段通過請求頭攜帶到服務(wù)器。注意: 第一次訪問服務(wù)器是不可能攜帶cookie的擅憔。

缺陷: 1鸵闪、cookie的數(shù)據(jù)存放在客戶端,不安全暑诸,容易被(CSRF)跨站請求偽造岛马。攻擊者可以借助受害者的 Cookie 騙取服務(wù)器的信任,可以在受害者毫不知情的情況下以受害者名義偽造請求發(fā)送給受攻擊服務(wù)器屠列,從而在并未授權(quán)的情況下執(zhí)行在權(quán)限保護之下的操作。2伞矩、單個cookie保存的數(shù)據(jù)不能超過4K笛洛,很多瀏覽器都限制一個站點最多保存20個cookie。

  1. Koa中使用cookie
  • 設(shè)置cookie
ctx.cookies.get(name, [options])

通過 options 獲取 cookie name:

signed 所請求的cookie應(yīng)該被簽名

  • 設(shè)置cookie
ctx.cookies.set(name, value, [options])

通過 options 設(shè)置 cookie name 的 value:

  • maxAge: 有效期(一個數(shù)字表示從 Date.now() 得到的毫秒數(shù))
  • signed: cookie 簽名值
  • expires: cookie 過期的 Date
  • path: cookie作用域(指定了主機下的哪些路徑可以接受Cookie), 默認(rèn)是 /
  • domain: cookie作用域 (指定了哪些主機可以接受Cookie乃坤。如果不指定苛让,默認(rèn)為當(dāng)前文檔的主機<不包含子域名>;如果指定了Domain,則一般包含子域名湿诊。
  • secure: 安全 cookie狱杰。即標(biāo)記為 Secure 的Cookie只可以通過被HTTPS協(xié)議加密過的請求發(fā)送給服務(wù)端。
  • httpOnly: 只可讓服務(wù)器通過http請求訪問cookie,不可通過js的document.cookieAPI訪問厅须,可以避免XSS攻擊仿畸。 默認(rèn)是 true。
  • SameSite: 允許服務(wù)器要求某個cookie在跨站請求時不會被發(fā)送朗和,從而可以阻止跨站請求偽造攻擊(CSRF)错沽。可選值:
    1. None:瀏覽器會在同站請求眶拉、跨站請求下繼續(xù)發(fā)送cookies千埃,不區(qū)分大小寫。
    2. Strict: 瀏覽器將只在訪問相同站點時發(fā)送cookie忆植。
    3. Lax: 在新版本瀏覽器中放可,為默認(rèn)選項谒臼。大多數(shù)情況不發(fā)送第三方 Cookie,只有當(dāng)用戶從外部站點導(dǎo)航到URL時才會發(fā)送耀里,包括鏈接(a標(biāo)簽)蜈缤、預(yù)加載(link)、get表單备韧。
  • overwrite: 一個布爾值劫樟,表示是否覆蓋以前設(shè)置的同名的 cookie (默認(rèn)是 false). 如果是 true, 在同一個請求中設(shè)置相同名稱的所有 Cookie(不管路徑或域)是否在設(shè)置此Cookie 時從 Set-Cookie 標(biāo)頭中過濾掉。
設(shè)置中文cookie

通過buffer轉(zhuǎn)成base64存進(jìn)去织堂,取出來是再轉(zhuǎn)回中文叠艳。

// 轉(zhuǎn)base64
Buffer.from('張三').toString('base64');

// 轉(zhuǎn)回中文
Buffer.from(buf, 'base64').toString();
session
  1. seeion簡單介紹

session是另一種記錄客戶狀態(tài)的機制,不同的是cookie保存在客戶端瀏覽器中易阳,而session保存在服務(wù)器上附较。

前面說過,cookie 是存放在客戶端潦俺,不是很安全拒课,用戶可以自己手動把cookie種在客戶端以欺騙服務(wù)器。而session是存儲在服務(wù)端的事示,所以對于較重要的數(shù)據(jù)存儲在session早像。

缺點: session會在一定時間內(nèi)保存在服務(wù)器上。當(dāng)訪問增多肖爵,會比較占用你服務(wù)器的性能卢鹦。

  1. session 的工作機制

當(dāng)瀏覽器第一次請求服務(wù)器時,服務(wù)器端會創(chuàng)建一個session對象劝堪,生成一個類似于key-value的鍵值對冀自, 然后將key(cookie)下發(fā)到客戶端,當(dāng)客戶端再訪問時秒啦,攜帶key(cookie)熬粗,找到對應(yīng)的session(value)。 生產(chǎn)中用戶的信息都保存在session中余境。

  1. koa-session 的使用
npm install koa-session
const Koa = require('koa');
const session = require('koa-session');

const app = new Koa();

app.keys = ['some secret hurr'];
 
const CONFIG = {
  key: 'koa:sess',      // 返給瀏覽器 cookie 的key 默認(rèn)是 'kao:sess'
  maxAge: 86400000,     // cookie的過期時間 maxAge in ms (default is 1 days)
  autoCommit: true,     // (boolean) 自動給客戶端下發(fā)cookie 并設(shè)置session
  overwrite: true,      // 是否可以覆蓋之前同名的cookie    (默認(rèn)default true)
  httpOnly: true,       // cookie是否只有服務(wù)器端可以訪問 httpOnly or not (default true)
  signed: true,         // 簽名默認(rèn)true
  rolling: false,       // 在每次響應(yīng)時強制設(shè)置session標(biāo)識符cookie驻呐,到期時被重置設(shè)置過期倒計時。(默認(rèn)為false)
  renew: false,         // 當(dāng)session快過期時更新session芳来,這樣就可以始終保持用戶登錄 默認(rèn)是false
};

以上配置選項常用的就是key暴氏、maxAge、httpOver绣张。

renew應(yīng)用:比如我們登錄賬號寫一篇博客答渔,寫了一半cookie過期了,當(dāng)我們提交的時候就會退出登錄侥涵,體驗很不好沼撕,而且寫好的博客丟失宋雏。

九、重定向

301和302重定向狀態(tài)碼區(qū)別务豺。302為臨時重定向磨总,301永久重定向。Koa中默認(rèn)為302笼沥。詳細(xì)信息查看這篇博客 301和302重定向介紹

字符串 “back” 是特別提供Referrer支持的蚪燕,當(dāng)Referrer不存在時,使用 alt 或“/”奔浅。

ctx.redirect('back');
ctx.redirect('back', '/login');
ctx.redirect('/login');

要更改 “302” 的默認(rèn)狀態(tài)馆纳,只需在該調(diào)用之前或之后分配狀態(tài)。要變更主體請在此調(diào)用之后:

ctx.status = 301;
ctx.redirect('/cart');
ctx.body = 'Redirecting to shopping cart';

十汹桦、跨域請求

解決跨域的方式有很多種鲁驶,個人認(rèn)為最好的方案是在服務(wù)器端設(shè)置支持跨域。

原生設(shè)置方式:

下面詳細(xì)說明在koa2中設(shè)置具體的請求頭信息:

app.use(async (ctx, next) => {
    // 允許所有域名請求
    ctx.set("Access-Control-Allow-Origin", "*")
    //  只允許 http://localhost:8080 域名的請求
    // ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");

    // 設(shè)置允許的跨域請求方式
    ctx.set("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE")

    // 字段是必需的舞骆。值一個逗號分隔的字符串钥弯,表示服務(wù)器所支持的所有頭信息字段.
    ctx.set("Access-Control-Allow-Headers", "x-requested-with, accept, origin, content-type")

    // 服務(wù)器收到請求以后,檢查了Origin督禽、Access-Control-Request-Method和Access-Control-Request-Headers字段以后脆霎,確認(rèn)允許跨源請求,即可做出響應(yīng)狈惫。

    // Content-Type表示具體請求中的媒體類型信息
    ctx.set("Content-Type", "application/json;charset=utf-8")

    // 該字段可選睛蛛。它的值是一個布爾值,表示是否允許發(fā)送Cookie虱岂。默認(rèn)情況下,Cookie不包括在CORS請求之中菠红。 當(dāng)設(shè)置成允許請求攜帶憑證cookie時第岖,需要保證"Access-Control-Allow-Origin"是服務(wù)器有的域名,而不能是"*";
    ctx.set("Access-Control-Allow-Credentials", true);

    // 該字段可選试溯,用來指定本次預(yù)檢請求的有效期蔑滓,單位為秒。
    // 當(dāng)請求方法是PUT或DELETE等特殊方法或者Content-Type字段的類型是application/json時遇绞,服務(wù)器會提前發(fā)送一次請求進(jìn)行驗證
    // 下面的的設(shè)置只本次驗證的有效時間键袱,即在該時間段內(nèi)服務(wù)端可以不用進(jìn)行驗證
    ctx.set("Access-Control-Max-Age", 300);

    /*
    CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:
        Cache-Control摹闽、
        Content-Language蹄咖、
        Content-Type、
        Expires付鹿、
        Last-Modified澜汤、
        Pragma蚜迅。
    */
    // 需要獲取其他字段時,使用Access-Control-Expose-Headers俊抵,
    // getResponseHeader('myData')可以返回我們所需的值
    ctx.set("Access-Control-Expose-Headers", "myData")

    await next()
})
使用中間件方式

在koa2中谁不,解決跨域請求還可使用中間件koa2-cors

  1. 安裝:
npm i koa2-cors -S
  1. 注冊中間件
const cors = require('koa2-cors')
app.use(cors())

十一、node發(fā)送郵件

node 發(fā)送郵件可以使用nodemailer三方模塊徽诲。

安裝:

npm i nodemailer

const nodemailer = require("nodemailer")

async function main() {
  let transporter = nodemailer.createTransport({
    host: "smtp.qq.com",
    port: 465,
    secure: true, // true for 465, false for other ports
    auth: {
      user: 'test@qq.com', 
      pass: 'akphfubplzqdbdfh'
    }
  })

  let info = await transporter.sendMail({
    from: 'test@qq.com', // sender address
    to: "bar@qq.com", // 接收地址 多個郵箱使用 ','分割
    subject: "Hello 老胖", // 郵件主題
    text: "胖子蹲啊胖子蹲胖子蹲完瘦子蹲", // plain text body
    // html: "<b>嗯好</b>" // html body
  })

  console.log("Message sent: %s", info.messageId)
  console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info))
}

main().catch(console.error)

使用說明:

  1. 創(chuàng)建transporter配置信息
    node_modules>nodemailer>lib>well_known>services.json中查看對應(yīng)的配置信息刹帕。配置發(fā)件郵箱相應(yīng)的host、port及secure谎替。

  2. 獲取發(fā)件箱密碼(類似于授權(quán)偷溺,獲取key),以qq郵箱為例
    qq郵箱>設(shè)置>賬戶>POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服務(wù)院喜,點擊開啟獲取pass

    授權(quán).png
  3. 配置user和pass

    1. user即發(fā)件地址
    2. pass就是剛才授權(quán)獲取的密碼
  1. sendMail配置信息

    1. from 發(fā)件地址
    2. to 收件地址 如果多個收件地址亡蓉,用 ,分割即可
    3. subject 郵件主題
    4. text 文件內(nèi)容
    5. html html內(nèi)容

    注意:text和html只能配置一個

更多詳細(xì)配置信息及功能參照官網(wǎng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市喷舀,隨后出現(xiàn)的幾起案子砍濒,更是在濱河造成了極大的恐慌,老刑警劉巖硫麻,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爸邢,死亡現(xiàn)場離奇詭異,居然都是意外死亡拿愧,警方通過查閱死者的電腦和手機杠河,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浇辜,“玉大人券敌,你說我怎么就攤上這事×螅” “怎么了待诅?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長熊镣。 經(jīng)常有香客問我卑雁,道長,這世上最難降的妖魔是什么绪囱? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任测蹲,我火速辦了婚禮,結(jié)果婚禮上鬼吵,老公的妹妹穿的比我還像新娘扣甲。我一直安慰自己,他們只是感情好齿椅,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布文捶。 她就那樣靜靜地躺著荷逞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粹排。 梳的紋絲不亂的頭發(fā)上种远,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音顽耳,去河邊找鬼坠敷。 笑死,一個胖子當(dāng)著我的面吹牛射富,可吹牛的內(nèi)容都是我干的膝迎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼胰耗,長吁一口氣:“原來是場噩夢啊……” “哼限次!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柴灯,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤卖漫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赠群,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羊始,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年查描,在試婚紗的時候發(fā)現(xiàn)自己被綠了突委。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡冬三,死狀恐怖匀油,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情勾笆,我是刑警寧澤敌蚜,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站匠襟,受9級特大地震影響钝侠,放射性物質(zhì)發(fā)生泄漏该园。R本人自食惡果不足惜酸舍,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望里初。 院中可真熱鬧啃勉,春花似錦、人聲如沸双妨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泣特,卻和暖如春浩姥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背状您。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工勒叠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膏孟。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓眯分,卻偏偏與公主長得像,于是被迫代替她去往敵國和親柒桑。 傳聞我的和親對象是個殘疾皇子弊决,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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