基于nodejs的Express框架以及GraphQL的JavaScript實(shí)現(xiàn)構(gòu)建一個(gè)簡(jiǎn)單的GraphQL服務(wù)器

GraphQL是什么春塌?

GraphQL 是Facebook開發(fā)的一個(gè)應(yīng)用層查詢語言. 后端定義基于圖的模式. 客戶端可以按需查詢需要的數(shù)據(jù)猾瘸。GraphQL也并不是一個(gè)具體的后端編程框架秉馏,如果將REST看做適合于簡(jiǎn)單邏輯的查詢標(biāo)準(zhǔn),那么GraphQL可以做一個(gè)獨(dú)立的抽象層越走,通過對(duì)于多個(gè)REST風(fēng)格的簡(jiǎn)單的接口的排列組合提供更多復(fù)雜多變的查詢方式蜜氨。與REST相比蚜迅,GraphQL定義了更嚴(yán)格、可擴(kuò)展诬乞、可維護(hù)的數(shù)據(jù)查詢方式册赛。

GraphQL

這個(gè)圖展示的是查詢流程钠导,查詢流程分為幾個(gè)步驟, 涉及多個(gè)組件, 包括客戶端應(yīng)用程序(Web, 手機(jī), 桌面等App), 一個(gè)GraphQL服務(wù)器用于解析查詢, 以及多個(gè)不同的數(shù)據(jù)來源。

GraphQL與之前Netflix出品的Falcor森瘪,都是致力于解決相同的問題:如何有效處理日益增長(zhǎng)不斷變化的Web/Mobile端復(fù)雜的數(shù)據(jù)需求辈双。REST最大的功勞在于前后端分離與無狀態(tài)請(qǐng)求,而REST的資源化的請(qǐng)求方式只適合面向簡(jiǎn)單的請(qǐng)求柜砾,對(duì)于具有復(fù)雜資源間關(guān)聯(lián)的請(qǐng)求就有點(diǎn)無能為力湃望。

如果你是學(xué)習(xí)后端的應(yīng)該知道REST API需要為每個(gè)請(qǐng)求匹配相應(yīng)的數(shù)據(jù)需求。而GraphQL的優(yōu)點(diǎn)在與客戶端數(shù)據(jù)要求發(fā)生變化時(shí), 不需要修改后端. 因此, 你不必因?yàn)榭蛻舳藬?shù)據(jù)需求的變更而改變你的后端痰驱。這解決了管理REST API中的最大的問題证芭。

為什么解決了REST API的大問題, 看如下闡述:

注解:
只要你的業(yè)務(wù)模型沒有發(fā)生變化, 從數(shù)據(jù)模型不會(huì)發(fā)生變化, 那么我們就不需要修改后端API。 前端按照需要的字段進(jìn)行查詢即可担映。如果業(yè)務(wù)發(fā)生了變化, 我們只需要修改GraphQL的模式定義, 并且實(shí)現(xiàn)對(duì)應(yīng)的服務(wù)器端數(shù)據(jù)查詢邏輯即可废士。傳統(tǒng)的REST查詢那些字段是固定的, 客戶端不能指定, GraphQL可以讓客戶端指定要獲取那些字段的數(shù)據(jù), 這給客戶端帶來了極大的靈活性, 讓前后端進(jìn)一步分離。查詢是可以嵌套的, 返回的JSON對(duì)象結(jié)構(gòu)和GraphQL查詢的結(jié)構(gòu)是一樣的, 這樣更方便客戶端自己定義數(shù)據(jù)的結(jié)構(gòu).

例如我們常見的需求蝇完,獲取了一篇博客文章和對(duì)應(yīng)評(píng)論與作者信息的數(shù)據(jù)官硝。

GraphQL同樣能夠讓客戶端程序高效地批量獲取數(shù)據(jù)。 例如, 看一看下面這個(gè)GraphQL請(qǐng)求:

{
  latestPost {
    _id,
    title,
    content,
    author {
      name
    },
    comments {
      content,
      author {
        name
      }
    }
  }
}

這個(gè) GraphQL 請(qǐng)求獲取了一篇博客文章和對(duì)應(yīng)評(píng)論與作者信息的數(shù)據(jù)短蜕。下面是請(qǐng)求的返回結(jié)果:

{
  "data": {
    "latestPost": {
      "_id": "03390abb5570ce03ae524397d215713b",
      "title": "New Feature: Tracking Error Status with Kadira",
      "content": "Here is a common feedback we received from our users ...",
      "author": {
        "name": "Pahan Sarathchandra"
      },
      "comments": [
        {
          "content": "This is a very good blog post",
          "author": {
            "name": "Arunoda Susiripala"
          }
        },
        {
          "content": "Keep up the good work",
          "author": {
            "name": "Kasun Indi"
          }
        }
      ]
    }
  }
}

如果你使用的是REST的話氢架,你要么需要前端查詢多次,要么需要去添加一個(gè)新的接口調(diào)用多個(gè)REST API的請(qǐng)求才能獲取這些信息朋魔,專門針對(duì)前端這種較為特殊的請(qǐng)求進(jìn)行響應(yīng)岖研,而這樣又不可避免地導(dǎo)致后端代碼的冗余,畢竟很有可能這個(gè)特殊的請(qǐng)求與返回哪天就被廢了警检。

GraphQL是一個(gè)規(guī)范

GraphQL是一個(gè)規(guī)范孙援,因此, 它可以用于任何平臺(tái)或語言。它有一個(gè)參考的實(shí)現(xiàn) JavaScript, 由Facebook維護(hù)扇雕。還有許多社區(qū)維護(hù)的實(shí)現(xiàn)有許多種語言拓售。之前我們用簡(jiǎn)短的描述說明了GraphQL是什么, 對(duì)其有了一個(gè)基本的映像, 現(xiàn)在我們通過實(shí)際的操作來感受GraphQL具體是一個(gè)什么東西。

首先在瀏覽器中打開: https://sandbox.learngraphql.com ,我們會(huì)看到下圖的GraphiQL查詢界面, 其界面窗口如下所示:

GraphiQL查詢界面

然后在左側(cè)的查詢窗口中輸入下面的查詢語句:

{
  posts (category: PRODUCT) {
    _id,
    title,
    summary
  }
}

然后右側(cè)出現(xiàn)如下內(nèi)容:

{
  "data": {
    "posts": [
      {
        "_id": "03390abb5570ce03ae524397d215713b",
        "title": "New Feature: Tracking Error Status with Kadira",
        "summary": "Lot of users asked us to add a feature to set status for errors in the Kadira Error Manager. Now, we've that functionality."
      },
      {
        "_id": "0be4bea0330ccb5ecf781a9f69a64bc8",
        "title": "What Should Kadira Build Next?",
        "summary": "We are working on the next few major feature releases for Kadira. We would like to know your preference. Pre-order the feature you would most like to see in the next major release (scheduled for August 1)."
      },
      {
        "_id": "19085291c89f0d04943093c4ff16b664",
        "title": "Awesome Error Tracking Solution for Meteor Apps with Kadira",
        "summary": "Error tracking is so much important and goes side by side with performance issues. This is the public beta announcement of Kadira's error tracking solution."
      },
      {
        "_id": "1afff9dfb0b97b5882c72cb60844e034",
        "title": "Tracking Meteor CPU Usage with Kadira",
        "summary": "We've replaced EventLoop Utilization chart with actual CPU Usage. See why?"
      },
      {
        "_id": "3d7a3853bf435c0f00e46e15257a94d9",
        "title": "Introducing Kadira Debug, Version 2",
        "summary": "Today, we are introducing a new version of Kadira Debug. It comes with many UI improvements and support for CPU profiling."
      }
    ]
  }
}

這個(gè)體驗(yàn)了一下GraphQL是怎么工作的镶奉。下面就該構(gòu)建案例

官方的簡(jiǎn)單的Quick Start教程

這里是以nodejs為基礎(chǔ)的础淤,所以需要nodejs環(huán)境請(qǐng)自行準(zhǔn)備。

首先創(chuàng)建項(xiàng)目文件夾腮鞍,然后進(jìn)入該文件在該目錄里打開控制臺(tái)值骇,然后使用npm安裝必要的依賴以及nodejs的express框架:

npm init // npm初始

再一路回車到entry point: (index.js)可以鍵入 app.js 或者你所希望的名稱,這里我們輸入app.js移国,這是當(dāng)前應(yīng)用的入口文件吱瘩。再一路回車。然后為了配合graphql我們需要進(jìn)行安裝相關(guān)依賴:

npm install express --save // 裝 Express 并將其保存到依賴列表中
npm install graphql express express-graphql --save // express-graphql
npm install babel --save
npm install body-parser --save

先創(chuàng)建一個(gè)名為 app.js 的文件迹缀,然后輸入以下代碼:

// Import the required libraries
var graphql = require('graphql');
var graphqlHTTP = require('express-graphql');
var express = require('express');

// Import the data you created above
var data = require('./data.json');

// 用“id”和“name”兩個(gè)字符串字段定義User類型使碾。User的類型是GraphQLObjectType蜜徽,他的子字段具有自己的類型(在這種情況下,GraphQLString)票摇。
var userType = new graphql.GraphQLObjectType({
  name: 'User',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
  }
});

// 定義一個(gè)頂級(jí)字段架構(gòu)“User”拘鞋,它接收一個(gè)參數(shù)“id”,并根據(jù)ID矢门,來返回用戶盆色。請(qǐng)注意,`query`是GraphQLObjectType祟剔,就像“User”隔躲。然而我們?cè)谏厦娑x的“user”這個(gè)字段,是一個(gè)userType物延。
var schema = new graphql.GraphQLSchema({
  query: new graphql.GraphQLObjectType({
    name: 'Query',
    fields: {
      user: {
        type: userType,
        // `args` describes the arguments that the `user` query accepts:` args `描述參數(shù)宣旱,接受` user`查詢。
        args: {
          id: { type: graphql.GraphQLString }
        },
        // 怎么去"resolve" 或者實(shí)現(xiàn)解決函數(shù)的描述叛薯?傳入查詢浑吟,在這種情況下,我們使用從上面的“ID”參數(shù)作為一個(gè)key耗溜,獲取來自'data'的'User'
        resolve: function (_, args) {
          return data[args.id];
        }
      }
    }
  })
});

express()
  .use('/graphql', graphqlHTTP({ schema: schema, pretty: true }))
  .listen(3000);

console.log('GraphQL server running on http://localhost:3000/graphql');

再創(chuàng)建一個(gè)名為data.json的文件组力,內(nèi)容如下:

{
  "1": {
    "id": "1",
    "name": "Dan"
  },
  "2": {
    "id": "2",
    "name": "Marie"
  },
  "3": {
    "id": "3",
    "name": "Jessie"
  }
}

在你創(chuàng)建的目錄下打開控制臺(tái),然后使用node命令啟動(dòng)服務(wù)器:

node app.js

運(yùn)行app.js强霎,默認(rèn)會(huì)打開:3000端口忿项,如果你直接訪問http://localhost:3000/graphql頁面會(huì)得到如下反饋:

{
  "errors": [
    {
      "message": "Must provide query string."
    }
  ]
}

然后我們?cè)谠撃夸浵麻_啟另一個(gè)控制臺(tái)蓉冈,鍵入以下內(nèi)容:

curl -XPOST -H "Content-Type:application/graphql"  -d '{ user(id:"1"){name} }' http://localhost:3000/graphql

然后會(huì)得到如下反饋:

{
  "data": {
    "user": {
      "name": "Dan"
    }
  }
}

再來一個(gè)例子:

我們把剛才的app.js里面的內(nèi)容進(jìn)行注釋城舞,然后寫入以下內(nèi)容:

var express = require('express');
var app = express();

var schema = require('./schema');
var graphql = require('graphql');
var bodyParser = require('body-parser');

app.use(bodyParser.text({ type: 'application/graphql' }));

app.post('/graphql', (req, res) => {
  // execute GraphQL!
  graphql.graphql(schema, req.body)
  .then((result) => {
    res.send(JSON.stringify(result, null, 2));
  });
});

app.get('/', function (req, res) {
  res.send('Hello World!');
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

同目錄下新建一個(gè)文件:schema.js

var graphql = require('graphql');

let count = 0;

let schema = new graphql.GraphQLSchema({
  query: new graphql.GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
      count: {
        type: graphql.GraphQLInt,
        resolve: function() {
          return count;
        }
      }
    }
  })
});

//把當(dāng)前模塊的路由暴露出去
module.exports = schema;

然后使用node命令啟動(dòng)服務(wù)器:

node app.js

運(yùn)行app.js,然后我們?cè)谠撃夸浵麻_啟另一個(gè)控制臺(tái)寞酿,鍵入以下內(nèi)容:

curl -XPOST -H "Content-Type:application/graphql"  -d 'query RootQueryType{ count }' http://localhost:3000/graphql

最終會(huì)得到如下反饋:

{
  "data": {
    "count": 0
  }
}

Express 應(yīng)用生成器創(chuàng)建簡(jiǎn)單的Quick Start應(yīng)用

上面的案例是入門的家夺,大部分情況下我們開發(fā)并不會(huì)這樣使用,我們大部分情況下需要通過 Express 應(yīng)用生成器創(chuàng)建應(yīng)用伐弹,首先我們需要全局安裝express:npm install express-generator -g拉馋,然后自己想一個(gè)文件名進(jìn)行express初始化:express -e 你的文件名(英文),這里我起的名字為nodejs_express惨好,然后初始化完成煌茴,它會(huì)提醒你如圖:

express -e 你的文件名
cd 你的文件名 && npm install
DEBUG=你的文件名:* npm start // 說明:?jiǎn)?dòng)這個(gè)應(yīng)用

然后在瀏覽器中打開 http://localhost:3000/ 網(wǎng)址就可以看到這個(gè)應(yīng)用了。

通過 Express 應(yīng)用生成器創(chuàng)建的應(yīng)用一般都有如下目錄結(jié)構(gòu):

初始目錄

為了配合graphql我們需要進(jìn)行安裝相關(guān)依賴

npm install express --save
npm install graphql express express-graphql --save
npm install babel --save

安裝完依賴我們?cè)陧?xiàng)目目錄下新建兩個(gè)文件一個(gè)是dao日川,一個(gè)是graphql蔓腐,在dao文件下新建一個(gè)data.json文件,在graphql文件下新建index.js龄句,效果如圖:

目錄

這里我們使用我們新建的文件和app.js回论,其他的文件暫時(shí)用不到散罕。

/dao/data.json 還是上面的內(nèi)容:

{
  "1": {
    "id": "1",
    "name": "Dan"
  },
  "2": {
    "id": "2",
    "name": "Marie"
  },
  "3": {
    "id": "3",
    "name": "Jessie"
  }
}

然后我們打開app.js,這里面是框架默認(rèn)配置傀蓉,我們需要在這里面引入我們剛才添加配置的依賴和我們需要的文件欧漱,在var app = express();這句代碼上面添加這些代碼:

//添加項(xiàng)
var ejs = require('ejs');

// 自需引入模塊------
var graphql = require('graphql');
var graphqlHTTP = require('express-graphql');
var graphqlIndex = require('./graphql/index.js');
// 自需引入模塊------

在它下面添加這些代碼:

// 自需引入模塊使用------
app.use('/graphql', graphqlHTTP({ schema: graphqlIndex, pretty: true }))
// 自需引入模塊使用------

app.js的整體:

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var index = require('./routes/index');
var users = require('./routes/users');

//添加項(xiàng)
var ejs = require('ejs');

// 自需引入模塊------
var graphql = require('graphql');
var graphqlHTTP = require('express-graphql');
var graphqlIndex = require('./graphql/index.js');
// 自需引入模塊------

var app = express();

// 自需引入模塊使用------
app.use('/graphql', graphqlHTTP({ schema: graphqlIndex, pretty: true }))
// 自需引入模塊使用------

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

/graphql/index.js 的內(nèi)容如下:

// Import the required libraries
var graphql = require('graphql');

var express = require('express');

// Import the data you created above
var data = require('../dao/data.json');

// 用“id”和“name”兩個(gè)字符串字段定義User類型。User的類型是GraphQLObjectType葬燎,他的子字段具有自己的類型(在這種情況下误甚,GraphQLString)。
var userType = new graphql.GraphQLObjectType({
  name: 'User',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
    id_card: { type: graphql.GraphQLString },
  }
});

// 定義一個(gè)頂級(jí)字段架構(gòu)“User”谱净,它接收一個(gè)參數(shù)“id”靶草,并根據(jù)ID,來返回用戶岳遥。請(qǐng)注意奕翔,`query`是GraphQLObjectType,就像“User”浩蓉。然而我們?cè)谏厦娑x的“user”這個(gè)字段派继,是一個(gè)userType。
var schema = new graphql.GraphQLSchema({
  query: new graphql.GraphQLObjectType({
    name: 'Query',
    fields: {
      user: { // user-查詢名
        type: userType,
        // `args` describes the arguments that the `user` query accepts:` args `描述參數(shù)捻艳,接受` user`查詢驾窟。
        args: {
          id: { type: graphql.GraphQLString }
        },
        // 怎么去"resolve" 或者實(shí)現(xiàn)解決函數(shù)的描述?傳入查詢认轨,在這種情況下绅络,我們使用從上面的“ID”參數(shù)作為一個(gè)key,獲取來自'data'的'User'
        resolve: function (_, args) {
          return data[args.id]; // 返回id
        }
      }
    }
  })
});
// curl -XPOST -H "Content-Type:application/graphql"  -d '{ user(id:"1"){name} }' http://localhost:3000/graphql

//把當(dāng)前模塊的路由暴露出去
module.exports = schema;

我們?cè)谠擁?xiàng)目中使用DEBUG=你的文件名:* npm start的方式運(yùn)行項(xiàng)目嘁字,打開:3000端口恩急,如果你直接訪問http://localhost:3000/graphql頁面會(huì)得到如下反饋:

{
  "errors": [
    {
      "message": "Must provide query string."
    }
  ]
}

然后我們?cè)谠撃夸浵麻_啟另一個(gè)控制臺(tái),鍵入以下內(nèi)容:

curl -XPOST -H "Content-Type:application/graphql"  -d '{ user(id:"1"){name} }' http://localhost:3000/graphql

然后會(huì)得到如下反饋:

{
  "data": {
    "user": {
      "name": "Dan"
    }
  }
}

小結(jié):

到這里基本上構(gòu)建一個(gè)簡(jiǎn)單的基于nodejs的Express框架及GraphQL的javascript實(shí)現(xiàn)的簡(jiǎn)單服務(wù)器纪蜒。

同時(shí)在末尾放上參考網(wǎng)站衷恭,和相關(guān)學(xué)習(xí)網(wǎng)站:

GraphiQL入門
GraphiQL實(shí)驗(yàn)
GraphiQL入門指南
GraphiQL框架join-monster
搭建你的第一個(gè) GraphQL 服務(wù)器
GraphQL什么鬼
GraphiQL官網(wǎng)
從REST到GraphQL的思維變遷
[GraphQL系列教程-英文](https://learngraphql.com/basics/introduction
一系列的關(guān)于GraphQL相關(guān)的資源的搜集
GraphQL and Authentication
GraphQL.js-GraphQL的JavaScript實(shí)現(xiàn)
expressjs

提示:后面還有精彩敬請(qǐng)期待,請(qǐng)大家關(guān)注我的專題:web前端纯续。如有意見可以進(jìn)行評(píng)論随珠,每一條評(píng)論我都會(huì)認(rèn)真對(duì)待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末猬错,一起剝皮案震驚了整個(gè)濱河市窗看,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌倦炒,老刑警劉巖显沈,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異析校,居然都是意外死亡构罗,警方通過查閱死者的電腦和手機(jī)铜涉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遂唧,“玉大人芙代,你說我怎么就攤上這事「桥恚” “怎么了纹烹?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)召边。 經(jīng)常有香客問我铺呵,道長(zhǎng),這世上最難降的妖魔是什么隧熙? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任片挂,我火速辦了婚禮,結(jié)果婚禮上贞盯,老公的妹妹穿的比我還像新娘音念。我一直安慰自己,他們只是感情好躏敢,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布闷愤。 她就那樣靜靜地躺著,像睡著了一般件余。 火紅的嫁衣襯著肌膚如雪讥脐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天啼器,我揣著相機(jī)與錄音旬渠,去河邊找鬼。 笑死镀首,一個(gè)胖子當(dāng)著我的面吹牛坟漱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播更哄,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼腥寇!你這毒婦竟也來了成翩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤赦役,失蹤者是張志新(化名)和其女友劉穎麻敌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掂摔,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡术羔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年赢赊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片级历。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡释移,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寥殖,到底是詐尸還是另有隱情玩讳,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布嚼贡,位于F島的核電站熏纯,受9級(jí)特大地震影響叁执,放射性物質(zhì)發(fā)生泄漏誊辉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一涮阔、第九天 我趴在偏房一處隱蔽的房頂上張望叮盘。 院中可真熱鬧往扔,春花似錦、人聲如沸熊户。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嚷堡。三九已至蝗罗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝌戒,已是汗流浹背串塑。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留北苟,地道東北人桩匪。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像友鼻,于是被迫代替她去往敵國(guó)和親傻昙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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