代码改变世界

理解Express中间件

2018-11-04 17:39  龙恩0707  阅读(922)  评论(0编辑  收藏  举报

阅读目录

一:body-parser中间件

二:cookie-parser中间件

三:express-session 中间件

四:理解使用morgan记录操作日志

一:body-parser中间件

body-parser是一个HTTP请求体解析的中间件,该中间件的作用是解析客户端请求的body中的内容的,使用该模块可以解析JSON、Raw、文本、URL-encoded格式的请求体。

如何使用?

在项目的根目录下,执行命令,先下载 body-parser, 代码执行如下:

npm install body-parser --save

基本使用如下:

1. 首先需要引入进来: const bodyParser = require('body-parser');
2. 然后再进行解析,目前支持如下四种格式的解析,如下:

    1. 解析json数据:bodyParser.json(options)
    2. 解析二进制格式(比如Buffer数据流这样的):bodyParser.raw(options);
    3. 解析文本数据: bodyParser.text(options);
    4. 解析UTF-8的编码数据:bodyParser.urlencoded(options);

    bodyParser.json(options); 它返回一个仅解析json格式数据的中间件。该方法支持任意Unicode编码的请求体,且支持gzip和deflate编码的数据压缩。

options参数有如下选项,及各选项的含义分别如下解析:

1)inflate: 该参数默认为true,deflate压缩数据被压缩,设置为false,压缩数据会被拒绝。
2)limit: 设置请求的最大数据量,默认为 '100kb'。
3)reviver: 传递给JSON.parse()方法的第二个参数。
4)strict: 默认为true,仅会解析Array和Object两种格式,如果设置为false的话,就会解析所有的JSON.parse支持的格式。
5)type: 该选项用于设置为指定MIME类型的数据使用当前解析的中间件。该选项可以是一个函数或一个字符串,如果是字符串的话会
使用type-is来查找MIME类型;如果是函数的话,中间件会通过fn(req)来获取实际值,默认为 application/json.

bodyParser.raw(options); 它是返回一个将所有数据为Buffer格式处理的中间件。其后所有的req.body中会是一个Buffer值。

options参数有如下选项,及各选项的含义分别如下解析:

1)inflate: 该参数默认为true,deflate压缩数据被压缩,设置为false,压缩数据会被拒绝。
2)limit: 设置请求的最大数据量,默认为 '100kb'。
3)type: 该选项用于设置为指定MIME类型的数据使用当前解析的中间件。该选项可以是一个函数或一个字符串,如果是字符串的话会
使用type-is来查找MIME类型;如果是函数的话,中间件会通过fn(req)来获取实际值,默认为 application/octet-stream.

bodyParser.text(options); 它是返回一个仅处理字符串格式处理的中间件。该req.body所有的将会是一个字符串值。

options参数有如下选项,及各选项的含义分别如下解析:

1)defaultCharset: 如果Content-Type没有指定编码的话,默认为 'utf-8'.
2)inflate: 该参数默认为true,deflate压缩数据被压缩,设置为false,压缩数据会被拒绝。
3)limit: 设置请求的最大数据量,默认为 '100kb'。
4)type: 该选项用于设置为指定MIME类型的数据使用当前解析的中间件。该选项可以是一个函数或一个字符串,如果是字符串的话会
使用type-is来查找MIME类型;如果是函数的话,中间件会通过fn(req)来获取实际值,默认为 application/octet-stream.

bodyParser.urlencoded(options) 解析UTF-8编码的数据,返回一个处理urlencoded数据的中间件。
options参数有如下选项,及各选项的含义分别如下解析:

1)extended - 当设置为false时,会使用querystring库解析URL编码的数据;当设置为true时,会使用qs库解析URL编码的数据。后没有指定编码时,使用此编码。默认为true。
2)inflate - 设置为true时,deflate压缩数据会被解压缩;设置为true时,deflate压缩数据会被拒绝。默认为true。
3)limit - 设置请求的最大数据量。默认为'100kb'
4)parameterLimit - 用于设置URL编码值的最大数据。默认为1000
5)type - 该选项用于设置为指定MIME类型的数据使用当前解析中间件。这个选项可以是一个函数或是字符串,当是字符串是会使用type-is来查找MIMI类型;当为函数是,中间件会通过fn(req)来获取实际值。默认为application/octet-stream。

如上bodyParser有四种方法来解析不同的数据,但是在实际项目中,我们是如何使用的呢?
Express框架默认是使用body-parser作为请求体解析中间件的。我们可以在项目中的根目录下创建一个bodyParser.js代码如下:
因此在运行执行,我们还需要安装express框架;安装命令如下:

npm install --save express

bodyParser.js 代码如下:

const express = require('express');

const bodyParser = require('body-parser');

const app = express();

// 对不同的路由使用不同的内容类型来解析

// 创建 application/json 解析
const jsonParser = bodyParser.json();

// 创建 application/x-www-form-urlencoded解析
const urlencodedParser = bodyParser.urlencoded({ extended: false });

// post /a 获取URL编码的请求体
app.post('/a', urlencodedParser, function(req, res) {
  if (!req.body) {
    return res.sendStatus(400);
  }
  console.log(req.body);
  res.send('welcome,' + req.body.userName);
  res.end();
});

// post /b 获取URL编码的请求体
app.post('/b', jsonParser, function(req, res) {
  if (!req.body) {
    return res.sendStatus(400);
  }
  res.send('welcome,' + req.body.userName);
  res.end();
});

const port = process.env.port || 3000;

app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

如上代码,当我们使用post请求 http://127.0.0.1:3000/a 请求的时候,他们使用的是 application/x-www-form-urlencoded格式来解析的,我这边使用postman来演示下,如下所示:

当我们使用 post请求 http://127.0.0.01:3000/b 的时候,我们使用的是 application/json格式来解析的,那么 Postman 以raw 方式发送JSON 数据,如下图所示:

注意:如果在模拟器上以非JSON格式发送,则会获得一个空的JSON对象。

注意:如果我们 app.use(bodyParser.urlencoded({ extended: false })) 这样使用的话,那么它会全局使用所有的都是以 application/x-www-form-urlencoded 来进行解析的。如果单个路由使用了 格式来解析的话,那么使用的格式的优先级更高。

二:cookie-parser中间件

cookieParser中间件是用于获取web浏览器发送的cookie中的内容。因为http协议它是无状态的,用户从A页面跳转到B页面会发起http请求,当服务器端返回响应之后,当用户A继续访问其他页面的时候,服务器端无法获知该状态的,因此需要一个cookie来记录用户的状态。

至于http无状态的原因,当初为什么需要这么设计,官方文档是如下说明的:

1. HTTP最初的目的是为了提供一种发布和接收HTML页面的方法,那个时候只有纯粹静态HTML页面,因此不需要协议来保持状态。

2. 用户在收到响应的时候,一般会花一些时间来阅读页面,如果客户端和服务器端还保持连接的话,那么这个连接在大多数时候都将是空闲的,这是一种资源的浪费,因此HTTP最初的设计是短连接,即:客户端和服务端完成一次请求和响应之后就断开TCP连接,因此服务端无法知道客户端的下一个动作。

3. 这样设计也可以使HTTP协议更加的相对简单,那么这种简单可以赋予HTTP更强的扩展能力,因此比如session就是一种协议扩展。或者后来出现了CGI动态技术等。

而正是因为HTTP不能保持状态的原因,因此客户端会出现cookie来保存状态,及后面即将讲解的session。因此浏览器第一次向服务器发送请求,服务器会返回一个cookie给客户端浏览器,浏览器下一次发请求的时候,会把该cookie传递过去,因此服务器端就知道该cookie对应值,就能获取该状态的。

1) cookie是如何创建的?

express直接提供了对应的API,只要在响应中设置cookie即可,如下代码所示:

function(req, res, next) {
  res.cookie(name, value, [, options]);
}

如上代码,express会将其填入 Response Header中的Set-Cookie中,达到浏览器中设置cookie的作用的。

如上参数 options 类型为一个对象,可以使用的属性有如下:

domain: cookie在什么域名下有效,类型为String, 默认为网站的域名。
expires: cookie的过期时间,类型为Date, 如果没有设置或设置为0,那么该cookie只在这个会话中有校,关闭浏览器的话,那么cookie就会被浏览器删除。
httpOnly: 只能被web server访问。类型为布尔型(Boolean)
maxAge: 实现expires的功能,设置cookie的过期时间,类型为String,指明从现在开始,过多少毫秒以后,cookie到期。
path: cookie在什么路径下有校,默认为 '/'
secure:  只能被HTTPS使用,默认为false。
signed: 使用签名,默认为false。

一般简单的用法如下:

res.cookie('name', 'kongzhi', { domain: 'xxx.abc.com', path: '/', secure: true });

//cookie的有效期为900000ms
res.cookie('age', '30', { expires: new Date(Date.now() + 900000), httpOnly: true });

//cookie的有效期为900000ms
res.cookie('age', '30', { maxAge: 900000, httpOnly: true });

//cookie的value为对象
res.cookie('kongzhi1', { items: [1,2,3] });

res.cookie('kongzhi2', { items: [1,2,3] }, { maxAge: 900000 });

res.cookie('name', 'longen', { signed: true });

2)cookie是如何被删除的?
express也提供了api删除浏览器中的cookie,只需要调用对应的API即可,如下代码:

function(req, res, next) {
  res.clearCookie(name, [, options]);
}

3) cookie-parser 读取cookie
在使用 cookie-parser 插件之前,我们首先要安装该插件,运行命令如下:

npm install --save cookie-parser

使用的demo基本如下(在项目的根目录下新建 cookieParser.js, 代码如下):

//引入cookieparser 框架,读取客户端发送的cookie
const express = require('express');

const cookieParase = require('cookie-parser');

var app = express();

//如果没有,下面的req.cookies 会返回undefined
app.use(cookieParase());

app.use('/', function (req,res) {
    res.cookie('user', 'kongzhi');
    console.log(req.cookies);
    res.send('cookie我来了');
});
const port = process.env.port || 3001;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

使用浏览器访问 http://127.0.0.1:3001/ 然后再看下控制台,可以看到如下读取到了:

下面我们再来看个demo来理解使用cookie,首先需要有一个提交cookie的页面 cookie.html, 该页面显示一个 '提交cookie' 按钮,在用户点击该按钮后,客户端会创建一些cookie,然后使用 XMLHttpRequest对象向服务器端提交数据,该页面所有的cookie也会被提交上去,待接到服务器端响应数据后会将这些数据显示在页面中。

在项目的根目录中新建 cookie.html 代码如下:

<!DOCTYPE html> 
<html>
<head>
  <title>cookie</title>
  <meta charset="utf-8">
  <style>
    #result {
      font-size: 16px;
    }
  </style>
</head>
<body>
  <div id="app">
    <form id="form1" method="post" action='index.html'>
      <input type="button" value="提交cookie" onclick="cookieTest()" />
    </form>
    <div id="result"></div>
  </div>
  <script type="text/javascript">
    function cookieTest() {
      var xhr = new XMLHttpRequest();
      xhr.open('post', 'cookie.html', true);
      
      document.cookie = 'username=kongzhi';
      document.cookie = 'age=30';
      xhr.onload = function() {
        if (this.status === 200) {
          document.getElementById('result').innerHTML = this.response;
        }
      };
      xhr.send();
    }
  </script>
</body>
</html>

在项目中的根目录新建 testCookie.js 代码如下:

const express = require('express');

const cookieParase = require('cookie-parser');

const fs = require('fs');

const app = express();

app.use(cookieParase());

app.get('/cookie.html', function(req, res) {
  res.sendfile(__dirname + '/cookie.html');
});

app.post('/cookie.html', function(req, res) {
  for (const key in req.cookies) {
    res.write('cookie名:' +key);
    res.write(',cookie值为:'+req.cookies[key] + "<br/>");
  }
  res.end();
});

const port = process.env.port || 3002;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

然后我们进入项目中的根目录运行 node testCookie.js ,接着浏览器访问 http://127.0.0.1:3002/cookie.html 后点击提交,
可以看到如下显示了。如下所示:

三:express-session 中间件

session中间件用于保存用户数据提供一个session管理器,它和cookie类似,都是记录用户状态的,而与cookie不同的是:
cookie有如下限制:
1. cookie存储的大小最多为4kb。
2. cookie有域或路径的概念,并且最重要的一点是 cookie安全性很低,一般重要的信息,比如用户名和密码这样的不允许放入cookie里面的。

如上cookie有最主要上面两点的缺点,因此对于安全性的一些信息建议放到session上存储,session是保存到服务器上的。

session基本原理:当客户端向服务端请求时,会创建一个session标识(比如叫jsessionid)存在客户端的cookie当中,每次请求的时候服务器端首先会检查这个客户端的请求里面是否已经包含了一个session标识,如果已经包含了,那么服务器端就会根据该session标识把对应的数据检索出来,如果不包含的话,服务端会创建一个新的session标识传给客户端cookie中,以后客户端每次请求的时候,从cookie中获取该标识把它传递过来。

服务端执行session机制的时候会生成Session口令,在Tomcat默认会采用jsessionid这个值,但是在其他服务器上会有所不同,比如Connect默认会叫 connect_uid, 虽然把一些敏感信息放到cookie当中是不可取的,但是将口令放在cookie中还是可以的,如果口令被篡改了的话,就丢失了映射关系,也无法修改服务端存在的数据了,并且session的有效期是非常短的,一般为20分钟,如果在20分钟内客户端和服务器端没有产生交互,服务端会将数据删除掉。

express-session 是服务器端保存数据的中间件,安装命令如下所示:

npm install express-session --save

然后在js中引入后,再接着use即可,简单的代码如下:

const express = require('express');
const app = express();
const session = require('express-session');
app.use(session(options));

如上参数 options 值为一个对象,它有如下属性值:

key: String类型,用于指定用来保存session的cookie名称,默认为 connect.sid.
store: 属性值为一个用来保存session数据的第三方存储对象。
fingerprint: 属性值为一个自定义指纹生成的函数。
cookie: 属性值为一个用来指定保存session数据的cookie设置的对象,默认值为 {path: '/', httpOnly: true, maxAge: 14400000}, path是用于指定cookie保存的路径,httpOnly属性值用于指定是否只针对http保存的cookie,maxAge用于指定cookie的过期时间,单位为毫秒。

secret: 属性值为一个字符串,用来指定来对session数据进行加密的字符串。

下面我们来和cookie一样,做一个简单的demo,来理解下使用 session的实列。

在页面中index.html 有一个form表单post提交数据,页面一访问的时候,监听get请求,给session设置数据,比如用户名和密码这样的,然后当我按钮提交post请求的时候,我们在服务器端监听post请求,然后把刚刚保存的session数据打印出来,代码如下:

session.html 代码如下:

<!DOCTYPE html> 
<html>
<head>
  <title>cookie</title>
  <meta charset="utf-8">
  <style>
    #result {
      font-size: 16px;
    }
  </style>
</head>
<body>
  <div id="app">
    <form id="form1" method="post" action='session.html'>
      <input type="submit" />
    </form>
    <div id="result"></div>
  </div>
</body>
</html>

session.js 代码如下:

const express = require('express');
const fs = require('fs');
const app = express();
const cookieParase = require('cookie-parser');
const sessionParser = require('express-session');

app.use(cookieParase());
app.use(sessionParser({secret: 'test'}));

app.get('/session.html', function(req, res) {
  res.sendfile(__dirname+'/session.html');
  req.session.username = 'kongzhi111';
  req.session.password = '123456';
});

app.post('/session.html', function(req, res) {
  console.log(req.session.username);
  console.log(req.session.password);
  res.end();
});

const port = process.env.port || 3003;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

在命令行中,执行命令 node session.js, 然后在浏览器中 访问 http://127.0.0.1:3003/session.html ,点击按钮后,在命令行中打印如下信息,如下所示:

1)理解使用 http.IncomingMessage 中regenerate 方法重新生成一个session管理器

我们也可以使用 http.IncomingMessage对象的session属性值对象的 regenerate 方法重新生成一个session管理器,如下基本代码:

req.session.regenerate(function(err) {});

session.js 代码改成如下:

const express = require('express');
const fs = require('fs');
const app = express();
const cookieParase = require('cookie-parser');
const sessionParser = require('express-session');

app.use(cookieParase());
app.use(sessionParser({secret: 'test'}));

app.get('/session.html', function(req, res) {
  res.sendfile(__dirname+'/session.html');
  req.session.username = 'kongzhi111';
  req.session.password = '123456';
  req.session.regenerate(function(err) {
    if (err) {
      console.log('session重新初始化失败');
    } else {
      console.log('session被重新初始化');
    }
  });

});

app.post('/session.html', function(req, res) {
  console.log(req.session.username);
  console.log(req.session.password);
  res.end();
});

const port = process.env.port || 3003;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

在页面浏览器访问 http://127.0.0.1:3003/session.html 后,命令行中会打印 如下所示:

然后点击提交后,命令中打印如下:

2)理解使用 http.IncomingMessage 中的destroy方法销毁当前在用的session管理器

destroy使用方式如下:

req.session.destroy(function(err) {});

session.js 代码改成如下:

const express = require('express');
const fs = require('fs');
const app = express();
const cookieParase = require('cookie-parser');
const sessionParser = require('express-session');

app.use(cookieParase());
app.use(sessionParser({secret: 'test'}));

app.get('/session.html', function(req, res) {
  res.sendfile(__dirname+'/session.html');
  req.session.username = 'kongzhi111';
  req.session.password = '123456';
  req.session.destroy(function(err) {
    if (err) {
      console.log('session销毁失败');
    } else {
      console.log('session被销毁');
    }
  });

});

app.post('/session.html', function(req, res) {
  console.log(req.session.username);
  console.log(req.session.password);
  res.end();
});

const port = process.env.port || 3003;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

同理在浏览器中运行 http://127.0.0.1:3003/session.html 后,在命令行中看到如下信息:

然后当我们点击按钮后,在命令行中看到如下信息:

3)查看http.IncomingMessage对象的session中保存cookie属性的所有信息

session代码如下:

const express = require('express');
const fs = require('fs');
const app = express();
const cookieParase = require('cookie-parser');
const sessionParser = require('express-session');

app.use(cookieParase());
app.use(sessionParser({secret: 'test', cookie: {maxAge: 3600000}}));

app.get('/session.html', function(req, res) {
  res.sendfile(__dirname+'/session.html');
  console.log(req.session.cookie);
});

const port = process.env.port || 3003;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

查看效果如下:

4)使用http.IncomingMessage对象session对象获取cookie的剩余时间

session.js 代码如下:

const express = require('express');
const fs = require('fs');
const app = express();
const cookieParase = require('cookie-parser');
const sessionParser = require('express-session');

app.use(cookieParase());
app.use(sessionParser({secret: 'test', cookie: {maxAge: 3600000}}));

app.get('/session.html', function(req, res) {
  res.sendfile(__dirname+'/session.html');
  var h = 3600000;
  req.session.cookie.expires = new Date(Date.now() + h);
  req.session.cookie.maxAge = h;
  setTimeout(function() {
    console.log('cookie的剩余时间'+req.session.cookie.maxAge);
  }, 5000);
});

const port = process.env.port || 3003;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

打印如下所示:

我们最后再来看下浏览器请求头信息,如下:

请求头看到 服务器会返回 cookie 和 用于指定用来保存session的cookie名称,默认为 connect.sid, connect.sid 是session的签名,作用是知道session是否被修改过。

5)使用Express + session 实现用户登录

当我们登录淘宝网站的时候,登录成功后,我们没有点击退出按钮或有效期没有过期的情况下,我们把浏览器关闭掉,重新进入淘宝的首页会发现我们的session会话还一直保持登录状态,那么这个状态就是session帮我们保存下来的。那么它在node中是如何实现的呢?

用户登录的基本原理是:如果用户没有登录或者登录时用户名或密码错误的时候,那么服务器将该请求重定向到登录页,或者的话就登录成功,登录成功后,服务器需要记录保存该客户端的登录状态,那么下一次服务器请求主页的时候,会先判断客户端的登录状态,如果登录状态在
有效期内是有效的,就直接进入主页,否则的话,和之前一样会重定向到登录页面。

下面如何使用session来做这件事的呢?

下面我们需要如下目录结构

|-- demo1           # 项目根目录
| |--- login.html   # 登录页面
| |--- home.html    # 主页
| |--- app.js       # node服务端

至于 package.json 和项目是同目录的。下面先看下 login.html 代码如下:

<!DOCTYPE html> 
<html>
<head>
  <title>expree+session实现用户登录</title>
  <meta charset="utf-8">
</head>
<body>
  <div id="app">
    <form action="/login" method="post">
      <p>
        <label>用户名:</label>
        <input type="text" name="username" />
      </p>
      <p>
        <label>密码:</label>
        <input type="password" name="password" />
      </p>
      <input type="submit" value="提交" />
    </form>
  </div>
</body>
</html>

home.html 代码如下:

<!DOCTYPE html> 
<html>
<head>
  <title>expree+session实现用户登录</title>
  <meta charset="utf-8">
</head>
<body>
  <div id="app">
    <div>
      用户名:<span><%= username %></span>
      <a href="/logout">退出登录</a>
    </div>
  </div>
</body>
</html>

如上home.html 代码,使用了 <%= username %> 这样的语法,这个是ejs模板语法,因此我们需要安装一下 ejs 如下命令安装:

npm install ejs --save

下面我们再来看看服务器端 app.js 代码如何处理业务的,代码如下:

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

const session = require('express-session');
const bodyParser = require('body-parser');
const ejs = require('ejs').__express;

app.set('views', __dirname); // 设置模板目录
app.set('view engine', 'html'); // 设置模板引擎为 html
app.engine('html', ejs); // 使用ejs模板引擎解析html文件中ejs语法

app.use(bodyParser.json()); // 使用 body-parser中间件 json形式

// 解析UTF-8编码的数据,返回一个处理urlencoded数据的中间件
app.use(bodyParser.urlencoded({ extended: true })); 

// 使用session中间件 设置cookie相关的信息

app.use(session({
  secret: 'test', // 对 session id 相关的cookie 进行加密签名
  cookie: {
    maxAge: 1000 * 60 * 1  // 设置 session的有效时间,单位为毫秒,设置有效期为1分钟
  }
}));

// get 登录页面
app.get('/login', (req, res) => {
  res.sendFile(__dirname + '/login.html');
});

// 监听post表单事件 用户登录
app.post('/login', (req, res) => {
  // 这里没有连接数据库,所以用户名和密码假如是写死的,所以简单进行判断一下
  if (req.body.username === 'kongzhi' && req.body.password === '123456') {
    req.session.username = req.body.username; // 登录成功,把登录信息保存到session里面去了
    // 登录成功后,进行重定向到首页
    res.redirect('/');
  } else {
    // 用户名或密码登录错误
    res.json({
      'code': 1,
      'errorMsg': '账户或密码错误'
    });
  }
});

// 处理重定向首页的逻辑代码
app.get('/', (req, res) => {
  // 如果session有已经登录的用户名的话,且有效期有效的话,则到 home.html, 否则重定向到登录页面
  if (req.session.username) {
    res.render('home', {username: req.session.username});
  } else {
    res.redirect('login');
  }
});

// 处理退出的逻辑
app.get('/logout', (req, res) => {
  req.session.username = null; // 删除session
  // 重定向到登录页面
  res.redirect('login');
});

const port = process.env.port || 3004;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

首先在命令行中 执行 node app.js ,然后在浏览器中访问 http://127.0.0.1:3004 后,如下所示:

当我输入正确的用户名和密码成功后,如下图所示:

session的有效期是1分钟,在1分钟之内不管如何刷新页面,都是在home.html页面,1分钟之后,session过期了,再刷新页面会自动跳转到登录页面去了。这时候就需要重新登录了。当然在home页面,你可以点击退出按钮,退出到登录页面去。

四:理解使用morgan记录操作日志

morgan中间件是来记录详细的操作日志或错误日志的。

1)morgan 安装命令如下所示:

npm install --save morgan

2) 基本使用方式如下:

const express = require('express');
const app = express();
const morgan = require('morgan');
app.use(morgan(format, [, options]));

如上代码使用morgan, morgan(format, options);

参数 format(可选)该参数定义了几种日志格式,每种格式都有对应的名称,默认是default,详细有哪些格式,请看github官网(https://github.com/expressjs/morgan/#predefined-formats)

参数 options(可选),包含 stream, skip, immediate
stream: 日志输出流配置,默认是 process.stdout
skip: 是否跳过日志记录,使用方式看github上(https://github.com/expressjs/morgan/#skip)
immediate: 布尔值,默认false,含义是在请求返回后,再记录日志,如果为true的话,含义是一收到请求,就记录日志。

1)下面我们来看下简单的demo来理解下morgan的使用:

基本结构目录如下:

---morgan           #项目的文件夹
 |--- morgan.html   # html文件
 |--- morgan.js     # js文件

morgan.html 代码如下:

<!DOCTYPE html> 
<html>
<head>
  <title>morgan</title>
  <meta charset="utf-8">
</head>
<body>
  <div id="app">
    <form id="form1">
      <input type="text" id="username" />
      <input type="button" value='提交' onclick="clickFunc()"/>
    </form>
    <div id="result"></div>
  </div>
  <script type="text/javascript">
    function clickFunc() {
      var obj = {
        username: document.getElementById('username').value
      };
      var xhr = new XMLHttpRequest();
      xhr.open('POST', 'morgan.html', true);
      xhr.onload = function(e) {
        if (this.status === 200) {
          document.getElementById('result').innerHTML = this.response;
        }
      };
      xhr.send(JSON.stringify(obj));
    }
  </script>
</body>
</html>

morgan.js 代码如下:

const express = require('express');
const morgan = require('morgan');
const app = express();

// 使用中间件,'combined' 是日志显示的格式,具体看github上(https://github.com/expressjs/morgan/#predefined-formats)
app.use(morgan('combined'));

app.get('/morgan.html', (req, res) => {
  res.sendFile(__dirname + '/morgan.html');
});

// post 请求监听 
app.post('/morgan.html', (req, res) => {
  req.on('data', (data) => {
    console.log(data.toString());
    res.end();
  });
});

const port = process.env.port || 3005;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

当我们在项目的对应目录下 执行 node morgan.js 会启动服务器,然后在浏览器中 http://127.0.0.1:3005/morgan.html中访问的时候,会打印出如下信息:

当我们输入内容后,点击提交,会打印如下日志信息,如下所示:

2)如何将日志信息保存到文件内?
morgan提供了写入文件流将这些日志相关的信息保存到文件中,如下morgan.js代码改成如下:

const express = require('express');
const morgan = require('morgan');
const app = express();
const fs = require('fs');
const path = require('path');
const accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'));


// 使用中间件,'combined' 是日志显示的格式,具体看github上(https://github.com/expressjs/morgan/#predefined-formats)
app.use(morgan('combined', {stream: accessLogStream}));

app.get('/morgan.html', (req, res) => {
  res.sendFile(__dirname + '/morgan.html');
});

// post 请求监听 
app.post('/morgan.html', (req, res) => {
  req.on('data', (data) => {
    console.log(data.toString());
    res.end();
  });
});

const port = process.env.port || 3005;
app.listen(port, () => {
  console.log('http://127.0.0.1:%s', port)
});

如上代码,把日志信息写入文件中 在morgan.js 同级目录下会自动生成 access.log 日志文件。

上面所有的demo,可以到github上查看