NestJS從入門到跑路

僅做參考: 有些語(yǔ)法已經(jīng)廢棄某宪,

什么是NestJS

Nest 是一個(gè)漸進(jìn)的 Node.js 框架示血,可以在 TypeScript 和 JavaScript (ES6秧荆、ES7该镣、ES8)之上構(gòu) 建高效祠墅、可伸縮的企業(yè)級(jí)服務(wù)器端應(yīng)用程序侮穿。

Nest 基于 TypeScript 編寫(xiě)并且結(jié)合了 OOP(面向?qū)ο缶幊蹋現(xiàn)P(函數(shù)式編程)和 FRP (函數(shù)式響應(yīng)編程)的相關(guān)理念毁嗦。在設(shè)計(jì)上的很多靈感來(lái)自于 Angular亲茅,Angular 的很多模 式又來(lái)自于 Java 中的 Spring 框架,依賴注入狗准、面向切面編程等芯急,所以我們也可以認(rèn)為: Nest 是 Node.js 版的 Spring 框架。

Nest 框架底層 HTTP 平臺(tái)默認(rèn)是基于 Express 實(shí)現(xiàn)的驶俊,所以無(wú)需擔(dān)心第三方庫(kù)的缺失娶耍。 Nest 旨在成為一個(gè)與平臺(tái)無(wú)關(guān)的框架。 通過(guò)平臺(tái)饼酿,可以創(chuàng)建可重用的邏輯部件榕酒,開(kāi)發(fā)人員可以利用這些部件來(lái)跨越多種不同類型的應(yīng)用程序。 從技術(shù)上講故俐,Nest 可以在創(chuàng)建適配器 后使用任何 Node HTTP 框架想鹰。 有兩個(gè)支持開(kāi)箱即用的 HTTP 平臺(tái):express 和 fastify。 您 可以選擇最適合您需求的產(chǎn)品药版。

NestJs 的核心思想:就是提供了一個(gè)層與層直接的耦合度極小,抽象化極高的一個(gè)架構(gòu) 體系辑舷。

官網(wǎng):https://nestjs.com/

中文網(wǎng)站:https://docs.nestjs.cn/

GitHub: https://github.com/nestjs/nest

image

圖一只是說(shuō)明規(guī)范的模塊方式,實(shí)際上槽片,可以只有根模塊何缓,也可以劃分多個(gè)模塊肢础,互相依賴,只要不是循環(huán)引入就行碌廓。

Nestjs 的特性

  • 依賴注入容器
  • 模塊化封裝
  • 可測(cè)試性
  • 內(nèi)置支持 TypeScript
  • 可基于 Express 或者 fastify

腳手架nest-cli

安裝

npm i -g @nestjs/cli 或者 cnpm i -g @nestjs/cli 或者 yarn global add @nestjs/cli

創(chuàng)建

nest new nestdemo

相關(guān)指令

  • nest new 名稱 創(chuàng)建項(xiàng)目
  • nest -h/--help 幫助
  • nest g co 名稱 創(chuàng)建控制器
  • nest g s 名稱 創(chuàng)建服務(wù)
  • nest g mi 名稱 創(chuàng)建中間件
  • nest g pi 名稱 創(chuàng)建管道
  • nest g mo 名稱 創(chuàng)建模塊
  • nest g gu 名稱 創(chuàng)建守衛(wèi)

創(chuàng)建類型指令都可以指定文件路徑传轰,而且路徑全部是再src目錄下面,例如:
nest g co /aaa/bbb/user 則在src下面就會(huì)存在一個(gè)三級(jí)目錄谷婆,user的目錄下
有一個(gè)以u(píng)ser命名大寫(xiě)的控制器 UserController.ts文件

注意:凡是以腳手架創(chuàng)建的模塊慨蛙,控制器等等都會(huì)自動(dòng)添加到對(duì)應(yīng)配置位置,不需要手動(dòng)配置

控制器

Nest 中的控制器層負(fù)責(zé)處理傳入的請(qǐng)求, 并返回對(duì)客戶端的響應(yīng)纪挎。

import { Controller, Get } from '@nestjs/common';
@Controller('article')
export class ArticleController { 
    @Get() 
    index(): string { 
        return '這是 article 里面的 index'; 
    } 
    @Get('add') 
    add(): string { 
        return '這是 article 里面的 index'; 
    } 
}

關(guān)于 nest 的 return: 當(dāng)請(qǐng)求處理程序返回 JavaScript 對(duì)象或數(shù)組時(shí)期贫,它將自動(dòng)序列化為 JSON。但是异袄,當(dāng)它返回一個(gè)字符串時(shí)唯灵,Nest 將只發(fā)送一個(gè)字符串而不是序列化它。這使響應(yīng)處理變得簡(jiǎn)單:只需要返回值隙轻,Nest 負(fù)責(zé)其余部分埠帕。

Get Post通過(guò)方法參數(shù)裝飾器獲取傳值

基本栗子

nestjs 內(nèi)置裝飾器的時(shí)候必須得在@nestjs/common 模塊下面引入對(duì)應(yīng)的裝飾器

import { Controller, Get, Post } from '@nestjs/common'; 
@Controller('cats') 
export class CatsController { 
    @Post() 
    create(): string { 
        return 'This action adds a new cat'; 
    } 
    @Get() 
    findAll(): string { 
        return 'This action returns all cats'; 
    } 
}

Nestjs 也提供了其他 HTTP 請(qǐng)求方法的裝飾器 @Put() 、@Delete()玖绿、@Patch()敛瓷、 @Options()、 @Head()和 @All()

Nest中獲取請(qǐng)求參數(shù)

在 Nestjs 中獲取 Get 傳值或者 Post 提交的數(shù)據(jù)的話我們可以使用 Nestjs 中的裝飾器來(lái)獲取

@Request() req 
@Response() res 
@Next() next 
@Session() req.session 
@Param(key?: string) req.params / req.params[key] 
@Body(key?: string) req.body / req.body[key] 
@Query(key?: string) req.query / req.query[key] 
@Headers(name?: string) req.headers / req.headers[name]
import { Controller, Get, Post,Query,Body } from '@nestjs/common'; 
@Controller('news') 
export class NewsController { 
    @Get() 
    getAbout(@Query() query): string { 
        console.log(query); 
        //這里獲取的就是所有的 Get 傳值 
        return '這是 about'
    }

    //針對(duì)參數(shù)是 localhost:3000/news/list?id=zq&age=12
    @Get('list') 
    getNews(@Query('id') id):string { 
        console.log(id); 
        //這里獲取的就是 Get 傳值里面的 Id 的值 
        //如果@Query()則是整個(gè)id=zq&age=12的對(duì)象
        return '這是新聞' 
    }
    @Post('doAdd') 
    async addNews(@Body() newsData){ 
        console.log(newsData); 
        return '增加新聞’'
    } 
}

動(dòng)態(tài)路由

// 針對(duì)的參數(shù)是 /name/id這種類型斑匪,例如/name/1

@Get(':id') 
findOne(@Param() params): string { 
    console.log(params.id); 
    return `This action returns a #${params.id} cat`; 
}

補(bǔ)充: @Param() 裝飾器訪問(wèn)以這種方式聲明的路由參數(shù)呐籽,該裝飾器應(yīng)添 加到函數(shù)簽名中。@Param可以用在get或者post蚀瘸,但是都是針對(duì) localhost:3000/news/list?id=zq&age=12這種才可以獲取狡蝶,而針對(duì)body內(nèi)部都是獲取不到的,可以使用@Body

綜合案例

@Controller('news')
export class NewsController {
    //依賴注入
    constructor(private readonly newsService:NewsService){}
    @Get('pip')
    @UsePipes(new NewsPipe(useSchema))
    indexPip(@Query() info){
        // console.log(info);
        return info;
    }
    
    @Get()
    @Render('default/news')
    index(){
      return  {
          newsList:this.newsService.findAll()
      }
    }

    /**
     * 路由順序:如果此時(shí)訪問(wèn)http://localhost:3000/news/add
     * 則會(huì)正確執(zhí)行贮勃,如果把a(bǔ)dd移動(dòng)到:id下面贪惹,則只會(huì)執(zhí)行:id的
     */
    @Get('add')
    addData(@Query('id') id){
        return id+'------';
    }

    //同理,這個(gè)模糊匹配如果移動(dòng)到:id下面寂嘉,訪問(wèn)http://localhost:3000/news/aaa
    //也會(huì)只匹配:id的路由
    @Get('a*a')
    indexA(){
        return '模糊匹配';
    }

    //動(dòng)態(tài)路由  /add/1
    @Get(':id')
    indexB(@Param('id') id){
        return id;
    }
}

Swagger集成

中文文檔地址:https://docs.nestjs.cn/6/recipes?id=openapi-swagger

  • 安裝

npm install --save @nestjs/swagger swagger-ui-express

如果你正在使用fastify奏瞬,你必須安裝 fastify-swagger 而不是 swagger-ui-express

npm install --save @nestjs/swagger fastify-swagger

  • 引導(dǎo)
    • main.ts
    • 引入:import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
    • 編碼
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    const options = new DocumentBuilder()
        .setTitle('Cats example')
        .setDescription('The cats API description')
        .setVersion('1.0')
        //下面兩者結(jié)合組成請(qǐng)求基本路徑
        .setHost('http://www.baidu.com')
        .setBasePath('/api')
        // .addTag('cats') 分類
        .build();
const document = SwaggerModule.createDocument(app, options);
//指定文檔路徑
SwaggerModule.setup('api-docs', app, document);
await app.listen(3000);
}
bootstrap();

打開(kāi)http://localhost:3000/api-docs/#/,如下圖二

image

swagger基本使用

創(chuàng)建Dto

import { ApiModelProperty } from '@nestjs/swagger';
export class CreatePostDto{
  @ApiModelProperty({description:"應(yīng)用名稱",example:'示例值'})
  title:string
  @ApiModelProperty({description:"應(yīng)用內(nèi)容"})
  content:string
}

@ApiModelProperty() 裝飾器接受選項(xiàng)對(duì)象

export const ApiModelProperty: (metadata?: {
  description?: string;
  required?: boolean;  //代表是否必須存在該參數(shù)
  type?: any;
  isArray?: boolean;
  collectionFormat?: string;
  default?: any;
  enum?: SwaggerEnumType;
  format?: string;
  multipleOf?: number;
  maximum?: number;
  exclusiveMaximum?: number;
  minimum?: number;
  exclusiveMinimum?: number;
  maxLength?: number;
  minLength?: number;
  pattern?: string;
  maxItems?: number;
  minItems?: number;
  uniqueItems?: boolean;
  maxProperties?: number;
  minProperties?: number;
  readOnly?: boolean;
  xml?: any;
  example?: any;
}) => PropertyDecorator;

完整例子

只是入門泉孩,更多例子是使用規(guī)則查看文檔

import { Controller, Get, Post, Body, Query, Param } from '@nestjs/common';
import { AppService } from './app.service';
import { ApiUseTags, ApiOperation, ApiModelProperty } from '@nestjs/swagger';

class CreatePostDto{
  //默認(rèn)required都是true硼端,Model上面會(huì)有個(gè)紅色星號(hào),代表必須填寫(xiě)寓搬,
  //但是實(shí)際上swagger本身不會(huì)限制珍昨,只是告知作用,swagger本身請(qǐng)求正常
  @ApiModelProperty({description:"應(yīng)用名稱",example:'示例值',maxLength:1,required:false})
  title:string
  @ApiModelProperty({description:"應(yīng)用內(nèi)容"})
  content:string
}

@Controller('app')
@ApiUseTags('默認(rèn)標(biāo)簽')//其實(shí)是大分類
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('hello')
  @ApiOperation({title:"顯示hello"}) //api的title描述/注釋
  getHello(@Query() query,@Param() params): any[] {
    return this.appService.getHello();
  }

  @Post('create')
  @ApiOperation({title:"創(chuàng)建應(yīng)用"})
  createApp(@Body() body:CreatePostDto): CreatePostDto{
    return body;
  }

  @Get(':id')
  @ApiOperation({title:'應(yīng)用詳情'})
  detail(@Param('id') id:number){
      return{
        id
      }
  }
}

總結(jié):swagger本身注解只是告知作用,不同于graphql镣典,例如required本身是沒(méi)什么作用只是告知使用者需要填寫(xiě)兔毙,但是實(shí)際上需要與否還是程序控制;同理骆撇,不論填寫(xiě)不填寫(xiě)swagger都會(huì)進(jìn)行請(qǐng)求瞒御,最終結(jié)果以邏輯控制為準(zhǔn)父叙。

參數(shù)驗(yàn)證

安裝

npm i class-validator class-transformer --save

啟用全局管道
main.ts中

app.useGlobalPipes(new ValidationPipe())

導(dǎo)包
在需要使用參數(shù)校驗(yàn)的文件內(nèi)導(dǎo)入

    import { IsNotEmpty } from 'class-validator'

class CreatePostDto{
  @ApiModelProperty({description:"應(yīng)用名稱",example:'示例值'})
  //**此處就是**
  @IsNotEmpty({message:'我是沒(méi)填寫(xiě)title屬性的時(shí)候神郊,返回的給前端的錯(cuò)誤信息'})
  title:string
  @ApiModelProperty({description:"應(yīng)用內(nèi)容"})
  content:string
}

說(shuō)明: Nest 自帶兩個(gè)開(kāi)箱即用的管道,即 ==ValidationPipe== 和 ==ParseIntPipe==
補(bǔ)充:ParseIntPipe簡(jiǎn)單使用

可把id自動(dòng)轉(zhuǎn)換成Int類型

@Get(':id')
async findOne(@Param('id', new ParseIntPipe()) id) {
  return await this.catsService.findOne(id);
}

總結(jié): 內(nèi)置管道都支持全局趾唱,方法涌乳,參數(shù)三種級(jí)別的使用
文檔連接

靜態(tài)資源

官方文檔:https://docs.nestjs.com/techniques/mvc

app.useStaticAssets('public');

  • 栗子
async function bootstrap() {
  //指定平臺(tái)
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  //配置靜態(tài)資源
  //app.useStaticAssets(join(__dirname,'..','public'))
  
  //上面是直接訪問(wèn)http://localhost:3000/a.png
  //下面可以設(shè)置虛擬目錄http://localhost:3000/public/a.png
  // app.useStaticAssets(join(__dirname,'..','public'),{
  //   prefix:'/public/'
  // })

  //如下方式也可以,因?yàn)槟J(rèn)nest會(huì)去尋找根目錄下面的參數(shù)一文件夾
  app.useStaticAssets('public',{
    prefix:'/public/'  
  })
  await app.listen(3000);
}

注意:NestFactory.create<NestExpressApplication>(AppModule);指定了范型其實(shí)就是Nest的平臺(tái)甜癞,默認(rèn)使用的是express的平臺(tái)夕晓,因?yàn)殪o態(tài)資源涉及平臺(tái)的選擇所以必須指定了。

模板引擎

官方文檔:https://docs.nestjs.com/techniques/mvc

  • 安裝

cnpm i ejs --save

配置

app.setBaseViewsDir(join(__dirname, '..', 'views')) // 放視圖的文件
app.setViewEngine('ejs');

完整代碼

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
//靜態(tài)資源中間件依賴于具體平臺(tái)悠咱,所以可以先引入express
import { NestExpressApplication } from '@nestjs/platform-express';
// import { join } from 'path';

//此時(shí)下面如果使用path則就是path.join
// import * as  path from 'path';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.useStaticAssets('public',{
    prefix:'/public/'
  })

  //配置模板引擎,需要先安裝模板引擎
  // app.setBaseViewsDir(join(__dirname,'..','views'))
  app.setBaseViewsDir('views');
  app.setViewEngine('ejs');
  await app.listen(3000);
}
bootstrap();

==注意此處引入path的方式==

渲染頁(yè)面

@Controller('user')
export class UserController {
    @Get()
    @Render('default/user')
    index(){
        //注意一般有render的路由則return值都是給模板引擎使用的
        //所以nest會(huì)判斷蒸辆,一般都是對(duì)象,返回字符串會(huì)報(bào)錯(cuò)
        // return '用戶中心';
        //此處是字符串key還是直接命名都可以被ejs搜索到
        // return {"name":"zs",age:12}
    }
}

說(shuō)明:default指的是views下面的default文件夾內(nèi)部的user模板
重定向

import { Controller, Get, Post, Body,Response, Render} from '@nestjs/common';
 @Controller('user') 
 export class UserController { 
     @Get() 
     @Render('default/user') 
     index(){ 
         return {"name":"張三"}; 
    }
    @Post('doAdd') 
    doAdd(@Body() body,@Response() res){
         console.log(body); 
         res.redirect('/user'); //路由跳轉(zhuǎn) 
    } 
}

提供者

幾乎所有的東西都可以被認(rèn)為是提供者 - service, repository, factory, helper 等等析既。他們都可以通過(guò) constructor注入依賴關(guān)系躬贡,也就是說(shuō),他們可以創(chuàng)建各種關(guān)系眼坏。但事實(shí)上拂玻,提供者不過(guò)是一個(gè)用@Injectable() 裝飾器注解的類。

export interface Cat {
  name: string;
  age: number;
  breed: string;
}

import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';

@Controller('cats')
export class CatsController {
    //依賴注入
  constructor(private readonly catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}

cookie

安裝

cnpm instlal cookie-parser --save

在 main.ts 中引入 cookie-parser

import * as cookieParser from 'cookie-parser'

在 main.ts 配置中間件

    app.use(cookieParser());

設(shè)置 cookie

    res.cookie("name",'zhangsan',{maxAge: 900000, httpOnly: true});

獲取 Cookies

@Get('getCookies') 
getCookies(@Request() req){ 
    return req.cookies.name; 
}

cookie參數(shù)說(shuō)明
屬性 說(shuō)明
domain 域名
expires 過(guò) 期 時(shí) 間 ( 秒 ) 宰译, 在 設(shè) 置 的 某 個(gè) 時(shí) 間 點(diǎn) 后 該 Cookie 就 會(huì) 失 效 檐蚜, 如 expires=Wednesday, 09-Nov-99 23:12:40 GMT
maxAge 最大失效時(shí)間(毫秒),設(shè)置在多少后失效
secure 當(dāng) secure 值為 true 時(shí)沿侈,cookie 在 HTTP 中是無(wú)效闯第,在 HTTPS 中才有效
path 表示 cookie 影響到的路,如 path=/缀拭。如果路徑不能匹配時(shí)乡括,瀏覽器則不發(fā)送這 個(gè) Cookie
httpOnly 是微軟對(duì) COOKIE 做的擴(kuò)展。如果在 COOKIE 中設(shè)置了“httpOnly”屬性智厌,則通 過(guò)程序(JS 腳本诲泌、applet 等)將無(wú)法讀取到 COOKIE 信息,防止 XSS 攻擊產(chǎn)生
signed 表 示 是 否 簽 名 cookie, 設(shè) 為 true 會(huì) 對(duì) 這 個(gè) cookie 簽 名 铣鹏, 這 樣 就 需 要 用 res.signedCookies 而不是 res.cookies 訪問(wèn)它敷扫。被篡改的簽名 cookie 會(huì)被服務(wù)器拒絕,并且 cookie 值會(huì)重置為它的原始值,說(shuō)白了==加密==
相關(guān)代碼

http://www.reibang.com/p/eec0586409da

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末葵第,一起剝皮案震驚了整個(gè)濱河市绘迁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卒密,老刑警劉巖缀台,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異哮奇,居然都是意外死亡膛腐,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門鼎俘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哲身,“玉大人,你說(shuō)我怎么就攤上這事贸伐】碧欤” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵捉邢,是天一觀的道長(zhǎng)脯丝。 經(jīng)常有香客問(wèn)我,道長(zhǎng)伏伐,這世上最難降的妖魔是什么宠进? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮秘案,結(jié)果婚禮上砰苍,老公的妹妹穿的比我還像新娘。我一直安慰自己阱高,他們只是感情好赚导,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著赤惊,像睡著了一般吼旧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上未舟,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天圈暗,我揣著相機(jī)與錄音,去河邊找鬼裕膀。 笑死员串,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的昼扛。 我是一名探鬼主播寸齐,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了渺鹦?” 一聲冷哼從身側(cè)響起扰法,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毅厚,沒(méi)想到半個(gè)月后塞颁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吸耿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年祠锣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片珍语。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锤岸,死狀恐怖竖幔,靈堂內(nèi)的尸體忽然破棺而出板乙,到底是詐尸還是另有隱情,我是刑警寧澤拳氢,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布募逞,位于F島的核電站馋评,受9級(jí)特大地震影響放接,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜留特,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜕青。 院中可真熱鬧贺喝,春花似錦、人聲如沸躏鱼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春贸呢,著一層夾襖步出監(jiān)牢的瞬間镰烧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工楞陷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怔鳖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓固蛾,卻偏偏與公主長(zhǎng)得像结执,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子艾凯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345