Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

express,koa和egg的配置 #8

Open
Wscats opened this issue Mar 14, 2017 · 0 comments
Open

express,koa和egg的配置 #8

Wscats opened this issue Mar 14, 2017 · 0 comments

Comments

@Wscats
Copy link
Owner

Wscats commented Mar 14, 2017

Express

安装

可以参考Express官方文档
首先express环境

npm install express

image
编写配置文件index.js,并执行

node index/node index.js

处理请求

处理GET请求:配合req.query
处理POST请求:需要body-parser模块,配合req.body

GET POST JSONP COOKIE
req.query req.body req.query req.cookies
//npm install express
var express = require('express');
//npm install body-parser
var bodyParser = require("body-parser");
var app = express();
//配置静态文件夹,在本地public读取css,js,html等文件
app.use(express.static('public'));
//post请求需要body-parser模块处理
app.use(bodyParser.urlencoded({
	extended: false
}));
app.get('/', function(req, res) {
	res.send('Hello World!');
});
app.get('/home', function(req, res) {
	//get请求参数对象
	console.log('get请求参数对象:', req.query);
	res.send('get请求');
});
app.post('/home', function(req, res) {
	//post请求参数对象
	console.log('post请求参数对象:', req.body);
	res.send('post请求');
});
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);
});

匹配路由参数

app.get('/add/:id/:age', function(req, res) {
	//追加请求头
	res.append("Access-Control-Allow-Origin","*");
	//?id=xx&age=xxx
	console.log(req.query)
	//:id/:age
	console.log(req.params)
	res.send("Hello Oaoafly");
})

跨域

可在中间件中追加这句防止跨域

res.append("Access-Control-Allow-Origin","*");

模板文件

这个设置视图文件的放置地方,然后配置jade为其模板渲染引擎,这里也需要安装jade模块实现

//views, 放模板文件的目录,比如: 
app.set('views', './views')
//view engine, 模板引擎
app.set('view engine', 'jade')

然后安装对应的模板引擎npm包

npm install jade

然后创建一个views文件夹,并在里面新建一个xxxx.jade文件,内容如下

html
	head
	body
		h1 这是测试
		p 你好
			ul.hhh#ddd
				for n in news
					li=n.title

在中间件中添加如下关键代码,res.render("文件名可省略后缀",{需要渲染在模板上的数据})

app.get('/', function(req, res) {
	connection.query("select * from news",function(err,data){
	var content = "Hello Oaoafly";
	res.render("qianfeng",{
		//model
		name:'xie',
		name2:'lan',
		news:data
	    })
	})
	//res.send("<p style='color:red'>"+content+"</p>");
})

静态文件

Express提供了内置的中间件express.static来设置静态文件如:图片, CSS,JavaScript等

你可以使用express.static中间件来设置静态文件路径

例如,如果你将图片, CSS,JavaScript文件放在public目录下

app.js根目录下创建一个public文件夹,然后在代码中添加

app.use(express.static('public'));

设置完静态文件夹后我们可以用res.sendFile(文件路径)方法来把文件发送到前端

注意路径要用绝对路径__dirname + "/public/" + "upload.html"

app.get('/index.html', function (req, res) {
   res.sendFile(__dirname + "/public" + "index.html");
})

还有值得注意的一点就是,对于每个应用程序,可以有多个静态目录,比如你可以按上传的文件类型分目录,当我们找某张图片的时候就会从这几个静态文件夹中一起找取

app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));

连接数据库

连接数据库,可以安装mysql模块实现

var mysql = require("mysql");
var connection = mysql.createConnection({
		host: "localhost",
		user: "root",
		password: "",
		database: "asm"
})
//执行数据库连接 .close();
connection.connect();
app.post('/add', function(req, res) {
	//追加请求头
	res.append("Access-Control-Allow-Origin","*");
	console.log(req.body);
	connection.query("insert into news (title,text) values ('" + req.body.title + "','" + req.body.text + "')",function(err,data){
		console.log(data)
	})
	res.send("增加信息");
	
})

body-parser

npm install body-parser

然后通过app.use()方法调用

var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// parse application/x-www-form-urlencoded 
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json 
app.use(bodyParser.json())

cookie-parser

npm install cookie-parser

通过app.use()方法调用

var cookieParser = require('cookie-parser')
app.use(cookieParser())

然后在中间件中通过req.cookies获取前端页面的cookie,是一个通过处理的对象

module description
querystring 将GET请求url中的字符串信息进行转换
chalk 把控制台输出信息的字符串颜色改变
body-parser 将客户端通过POST方法传过来的req.body数据解析成json数据
cookie-parser 处理cookie信息
svg-captcha 用来生成验证码
trek-captcha 用来生成验证码
emailjs 用来通过邮箱找回密码
validator 验证器
mongodb 连接mongodb数据库
crypto express自带的加密模块
express-session session的认证机制离不开cookie,需要同时使用cookieParser中间件,可以用来保存用户的登陆状态,免密码登陆
formidable 表单文件上传模块

上传文件

node上传文件

热启动

npm install supervisor -g

全局安装后,就会有supervisor命令,它会自动检测你的文件变化,一旦变化则会自动重启

supervisor app.js

过滤器

可以设置对路由的拦截,比如用在登录拦截等

filter.js

exports.authorize = function(req, res, next) {
	if(req.body.token) {
		//res.redirect('/beauty/test');
		console.log(1)
	} else {
		//res.redirect('/beauty/getFemaleList');
		console.log(2)
		next();
	}
}

路由逻辑

var express = require('express');
var router = express.Router(); //模块化
var filter = require('../filter.js');
router.get('/getFemaleList', filter.authorize, function(req, res) {
	res.send('hello world');
});

此时访问/getFemaleList路由的时候就会进入过滤器逻辑,从而实现拦截功能

ES6

要让Express在ES6下跑起来就不得不用转码器Babel了。首先新建一个在某目录下新建一个项目。然后跳转到这个目录下开始下面的操作

全局安装

npm install --save-dev babel-cli -g

然后,可以安装一些presets

cnpm install --save-dev babel-preset-es2015 babel-preset-stage-2

package.json里添加运行的脚本,这里就可以用ES6代码写程序,babel自动帮我们转ES5运行

"scripts": {
    "start": "babel-node index.js --presets es2015,stage-2"
}

可以用babel lib -d dist命令将router文件夹的所有js转码

"scripts": {
    "start": "babel-node --presets es2015,stage-2",
    "build": "babel router -d dist --presets es2015,stage-2",
     "serve": "node dist/index.js"
}

脚手架

全局安装

npm install -g express-generator@4

在一个文件夹里面用express命令创建应用架构

express test
cd test

进入test文件夹安装依赖,推荐cnpm安装所有依赖

npm install

启动应用

SET DEBUG=test:*
npm start

访问在浏览器3000端口号

http://localhost:3000

创建路由

进入到test目录的routes文件夹,然后复制users.js

你可以改变/home这里的路径

var express = require('express');
var router = express.Router();
router.get('/home', function(req, res, next) {
  res.send('hello world');
});
module.exports = router;

app.js添加以下两条,该路由就完成了

var homeRouter = require('./routes/home');
//code
app.use('/test', homeRouter);

访问该路径

http://localhost:3000/test/home

配合await和async

let db = require("../libs/db.js");
router.post('/findUser', async (req, res, next) => {
  let {
    id,
    name,
    skill
  } = req.body
  let data = await db.connect(`select * from students where ?`, [{
    id
  }])
  res.send(data);
});

Koa

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。——引用Koa的官方文档的原话

所以Koa和Express框架其实很像,个人感觉Koa更轻量

安装

Koa依赖node v7.6.0ES2015及更高版本和async方法支持

npm i koa
node my-koa-app.js

安装完之后可以新建my-koa-app.js,然后写以下代码,就可以简单创建一个服务器

const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
  ctx.body = 'Hello World';
});
app.listen(3000);

处理请求和响应

Koa Contextnoderequestresponse对象封装到单个对象中,为编写 Web 应用程序和 API 提供了许多有用的方法,一般将它简写为ctx

ctx.request; // 这是 koa Request
ctx.req; // 这是 node Request
// 注意:绕过 Koa 的 response 处理是 不被支持的. 应避免使用以下 node 属性:res.statusCode, res.writeHead(), res.write(), res.end()

res.statusCode
res.writeHead()
res.write()
res.end()
ctx.request

ctx.response; // 这是 koa Response
ctx.res; // 这是 node Response

区别于express框架,是在回调函数里面分开写requestresponse

为方便起见许多上下文的访问器和方法直接委托给它们的ctx.requestctx.response,不然的话它们是相同的。 例如ctx.typectx.length委托给response对象ctx.pathctx.method委托给request。所以ctx上面综合封装了多个requestresponse的方法

下面这个负责响应请求体的数据

ctx.response.body=
ctx.body= // 简写

将响应体设置为以下之一:

string 写入
Buffer 写入
Stream 管道
Object || Array JSON-字符串化
null 无内容响应

也就是说如果传递数组或者字符串它会自动调用JSON.stringify()来序列化数据,并且response.status如未被设置, Koa将会自动设置状态为200204

Context

GET POST JSONP COOKIE
ctx.query ctx.request.body ctx.query ctx.cookies.get(name, [options])

注意post请求需要配合koa-bodyparser模块和x-www-form-urlencoded格式,如果是formdata 格式,可以用multer模块来解析

const bodyParser = require('koa-bodyparser'); // 需要先安装koa-bodyparser npm install koa-bodyparser
app.use(bodyParser());

Request别名
以下访问器和Request别名等效:

ctx.header
ctx.headers
ctx.method
ctx.method=
ctx.url
ctx.url=
ctx.originalUrl
ctx.origin
ctx.href
ctx.path
ctx.path=
ctx.query
ctx.query=
ctx.querystring
ctx.querystring=
ctx.host
ctx.hostname
ctx.fresh
ctx.stale
ctx.socket
ctx.protocol
ctx.secure
ctx.ip
ctx.ips
ctx.subdomains
ctx.is()
ctx.accepts()
ctx.acceptsEncodings()
ctx.acceptsCharsets()
ctx.acceptsLanguages()
ctx.get()

Response别名
以下访问器和Response别名等效:

ctx.body
ctx.body=
ctx.status
ctx.status=
ctx.message
ctx.message=
ctx.length=
ctx.length
ctx.type=
ctx.type
ctx.headerSent
ctx.redirect()
ctx.attachment()
ctx.set()
ctx.append()
ctx.remove()
ctx.lastModified=
ctx.etag=

Egg

安装

直接使用脚手架,可快速生成项目文件夹

npm i egg-init -g
egg-init egg-example --type=simple
cd egg-example
npm i

控制器

第一步需要编写的ControllerRouter

// app/controller/home.js(编写文件的位置)
const Controller = require('egg').Controller;
class HomeController extends Controller {
  async index() {
    this.ctx.body = 'Hello world';
  }
}
module.exports = HomeController;

配置路由映射

// app/router.js(编写文件的位置)
module.exports = app => {
  const { router, controller } = app;
  router.get('/', controller.home.index);
};

静态资源

Egg 内置了 static 插件,线上环境建议部署到 CDN,无需该插件
static 插件默认映射/public/* -> app/public/*目录
此处,我们把静态资源都放到app/public目录即可

跨域

config/config.default.js添加以下代码

config.security = {
  csrf: {
    enable: false,
    ignoreJSON: true, // 默认为 false,当设置为 true 时,将会放过所有 content-type 为 `application/json` 的请求
  },
  domainWhiteList: [ 'http://localhost:8000' ],
};
config.cors = {
  allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
};

并且在plugin.js添加以下代码

exports.cors = {
  enable: true,
  package: 'egg-cors',
};

服务

简单来说,Service 就是在复杂业务场景下用于做业务逻辑封装的一个抽象层,提供这个抽象有以下几个好处:

  • 保持 Controller 中的逻辑更加简洁。
  • 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。
  • 将逻辑和展现分离,更容易编写测试用例,测试用例的编写具体可以查看这里

所以我们可以把操作数据库的逻辑放在 Service 层

定义 Service 文件

// app/service/user.js
const Service = require('egg').Service;
class UserService extends Service {
  // 默认不需要提供构造函数。
  // constructor(ctx) {
  //   super(ctx); 如果需要在构造函数做一些处理,一定要有这句话,才能保证后面 `this.ctx`的使用。
  //   // 就可以直接通过 this.ctx 获取 ctx 了
  //   // 还可以直接通过 this.app 获取 app 了
  // }
  async find(uid) {
    // 假如 我们拿到用户 id 从数据库获取用户详细信息
    const user = await this.ctx.db.query('select * from user where uid = ?', uid);
    // 假定这里还有一些复杂的计算,然后返回需要的信息。
    const picture = await this.getPicture(uid);
    return {
      name: user.user_name,
      age: user.age,
      picture,
    };
  }
  async getPicture(uid) {
    const result = await this.ctx.curl(`http://photoserver/uid=${uid}`, { dataType: 'json' });
    return result.data;
  }
}
module.exports = UserService;

我们就可以在 Controller 层用this.ctx.service.服务名xxx.方法xxx来调用服务里面封装好的方法

// app/router.js
module.exports = app => {
  app.router.get('/user/:id', app.controller.user.info);
};
// app/controller/user.js
const Controller = require('egg').Controller;
class UserController extends Controller {
  async info() {
    const { ctx } = this;
    const userId = ctx.params.id;
    const userInfo = await ctx.service.user.find(userId);
    ctx.body = userInfo;
  }
}
module.exports = UserController;

服务器代理

可以使用curl来代替第三方request模块,或者内置的http.request模块来实现服务器代理通讯

class HomeController extends Controller {
  async news() {
    // 今日头条
    const { ctx } = this;
    const {
      data,
    } = await ctx.curl('https://m.toutiao.com/list/?tag=video&ac=wap&count=20&format=json_raw&as=A1457C764A41F74&cp=5C6AC19F07943E1&min_behot_time=0&_signature=1Y7F0AAAieymeM-.Mi2uANWOxc&i=', {
      dataType: 'json',
    });
    ctx.body = data;
  }
}
@Wscats Wscats changed the title express配置 express,koa和egg的配置 Feb 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant