foreword(前言)
上一篇文章中,我们已经大致介绍了express的基础语法,本篇文章将主要介绍express的一些进阶用法,大致为以下几点:
- express自定义模版引擎;
- 简单介绍process manager;
- express如何预防安全漏洞;
- express的性能优化操作;
express自定义模版引擎
上一篇文章中我们简单演示了pug模版引擎的使用,我们发现pug其实是通过npm下载下来的,所以我们会想,pug模版引擎是一个第三方包吗?
我们直接在npm官网直接搜索pug,会发现确实pug是一个第三方包,也就会生出express也许提供了某些关于模版引擎的api。确实是这样的,官网给出了自定义模版引擎的demo演示:
var fs = require('fs') // this engine requires the fs module
app.engine('ntl', function (filePath, options, callback) { // define the template engine
fs.readFile(filePath, function (err, content) {
if (err) return callback(err)
// this is an extremely simple template engine
var rendered = content.toString()
.replace('#title#', '<title>' + options.title + '</title>')
.replace('#message#', '<h1>' + options.message + '</h1>')
return callback(null, rendered)
})
})
app.set('views', './views') // specify the views directory
app.set('view engine', 'ntl') // register the template engine
上面代码中,通过express实例的一个engine方法可以进行模版引擎的定义,它提供两个参数:
- 模版名称(同样是模版文件后缀名);
- 一个回调函数,它的第一第二个参数将会接收express的render方法的第一第二参数;
关于engine方法具体可查看:http://expressjs.com/en/api.html#app.engine
完成上面操作之后,我们就可以声明一个index.pug文件,比如:
#title#
#message#
然后通过在路由handler中向客户端渲染页面即可:
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!' })
})
进程管理器(process manager)
进程管理器有点像应用程序服务器:它是应用程序的“容器”,可便于应用程序的部署,保证应用的高可用性并允许你在运行时管理应用程序。
当你在生产环境中运行应用程序,通过process manager,我们具体可以做到如下:
- 当应用运行奔溃时,它可以自动重启应用;
- 它可以实时监听应用运行时性能和资源消耗;
- 它可以动态调整配置以提高性能;
- 它可以控制集群;
目前针对express应用或者其他nodejs应用比较受欢迎的进程管理器主要有以下几个:
- Forever:https://github.com/foreverjs/forever;
- PM2:https://github.com/Unitech/pm2;
- StrongLoop Process Manager (Strong-PM):http://expressjs.com/en/advanced/pm.html
- SystemD:https://www.axllent.org/docs/view/nodejs-service-with-systemd/
express如何预防安全漏洞
1.不要使用过时或存在明显安全漏洞的express版本;(可以通过查阅这个地址:http://expressjs.com/en/advanced/security-updates.html查看express修复安全漏洞的情况)
2.如果你的应用包含一些比较敏感的数据,推荐使用TLS协议;
3.通过使用Helmet可以让你的应用预防某些比较知名的web安全漏洞,它的原理是帮你设置一些安全的http header消息头,而且它的用法也比较简单:
// ...
var helmet = require('helmet')
app.use(helmet())
// ...
Helmet实际上是12个更小的中间件方法组成的集合,默认情况下使用app.use(helmet())
并不会包含所有的中间件方法,具体使用情况如下:
Module | Default? |
---|---|
contentSecurityPolicy for setting Content Security Policy | |
crossdomain for handling Adobe products’ crossdomain requests | |
dnsPrefetchControl controls browser DNS prefetching | ✓ |
expectCt for handling Certificate Transparency | |
featurePolicy to limit your site’s features | |
frameguard to prevent clickjacking | ✓ |
hidePoweredBy to remove the X-Powered-By header | ✓ |
hsts for HTTP Strict Transport Security | ✓ |
ieNoOpen sets X-Download-Options for IE8+ | ✓ |
noSniff to keep clients from sniffing the MIME type | ✓ |
referrerPolicy to hide the Referer header | |
xssFilter adds some small XSS protections | ✓ |
其中它有几个中间件对预防安全漏洞有帮助:
- contentSecurityPolicy设置Content-Security-Policy消息头来预防跨站脚本攻击和其他跨站注入;
- hidePoweredBy用来移除X-Powered-By消息头;
- hsts设置Strict-Transport-Security消息头,以告诉浏览器在接下来的一段时间内只能通过https来进行访问;
- ieNoOpen用于将X-Download-Options消息头设置为noopen,以禁用ie浏览器在下载文件后不直接打开文件而是保存文件;(主要针对ie8+,这样做的目的是防止一些恶意的脚本直接在你的电脑中运行)
- nocache通过设置 Cache-Control和Pragma消息头来禁用客户端缓存;
- nosniff通过设置X-Content-Type-Options来预防浏览器的MIME-sniffing(不使用浏览器Content-Type标注的类型,而是通过检测判断返回的文件类型);
- frameguard通过设置X-Frame-Options消息头来避免点击劫持(clickjaking);
- xssFilter通过设置X-XSS-Protection来开启跨站脚本攻击的检测;(针对目前主流浏览器)
当然,如果你不想使用Helmet,至少你得禁用X-Powered-By消息头,比如在express中你可以这样做:
app.disable('x-powered-by')
4.安全地使用cookie:
- 不要使用默认的cookie键名;
- 常用的express中间件有express-session和cookie-session,两者的区别是,express-session会将session的id保存为cookie,而cookie-session将会完整地保存session的字段,如果数据比较敏感,express-session将会是更好的选择;
- 浏览器应该能支持每个cookie最多4096个字节,不过还要确保每个域名下cookie不超过4093个字节;
- 设置cookie的安全选项:
- secure -确保浏览器仅通过HTTPS发送cookie;
- httpOnly -确保cookie仅通过HTTP(S)发送,而不通过客户端JavaScript发送,从而有助于防止跨站点脚本攻击;(也就是说如果设置了httponly, 客户端就不能通过javascript获取cookie)
- domain-表示Cookie的域;使用它与请求URL的服务器域进行比较。如果它们匹配,则接下来检查path属性;
- path-指示cookie的路径;使用它与请求路径进行比较。如果与域匹配,则在请求中发送cookie;
- expires -用于设置永久性cookie的到期日期;
5.防止针对授权的暴力攻击,有以下两种策略:
- 针对相同的用户名和ip,尝试次数连续失败达到某个数值时,阻止授权尝试;
- 在一段时间内,针对相同的用户名和ip,尝试次数连续失败达到某个数值时,阻止授权;
6.保证你所依赖的包都是安全的:
- 可以通过npm audit来分析你的依赖树;
- 也可以通过synk来测试应用的安全漏洞;
7.实时了解安全漏洞可以让自己能更好地预防安全漏洞,你可以查阅一些网站来npm依赖的安全性程度,比如:https://www.npmjs.com/advisories和https://snyk.io/vuln/。
性能优化
主要分为两个部分,代码中的优化和环境/设置中的优化。
1.代码优化
- 使用gzip压缩;
- 不要使用同步方法,因为这会阻塞执行过程;
- 学会正确地打印日志,比如我们通常会通过console.log和console.error来打印日志,由于这两个方法都是同步方法,所以生产环境中不推荐使用他们;
- 正确处理异常:try-catch处理同步异常,promise处理异步异常;
2.环境/设置中的优化
- 将NODE_ENV设置为“ production”,这可以:缓存视图模板、缓存从css扩展生成的css文件、生成较少的详细错误信息;
- 确保您的应用程序能够自动重启;(也就可以用到我们之前说到的process manager)
- 在集群中运行您的应用;
- 缓存请求结果,以避免重复请求相同的结果,这也是提高生产性能的一种策略;
- 使用负载平衡器,
- 使用反向代理;
总结
本篇文章主要介绍了express的一些高阶用法,特别是安全漏洞和性能优化这两块是平时经常容易被忽略却又非常重要的。
常见的web安全漏洞有sql注入、跨站脚本漏洞、CSRF等,上面安全漏洞预防的某些方法中,会发现很多安全漏洞我们都可以从网络请求的方向去预防,可想而知http的掌握非常重要。
性能优化中的方法大多是依赖express的一些优化操作,如果以整个前端的角度去看待性能优化这个操作,从pc端到移动端,从首屏加载过程,从浏览器兼容角度,实际上要做的还有很多,而当我们将这些优化一个个都做好的时候,不仅给用户带来更佳的体验,同时也能让自己在之后能够写出更好的项目或自己的开源脚本、框架等。
下一期target
下一期,我将梳理项目搭建结构,并与express的generator进行比较(时间充足的情况下我将梳理generator源码结构,简单理清它的运行原理)
github讨论地址:https://github.com/yaodebian/blog/issues/22
last(最后)
非常感谢您能阅读完这篇文章,您的阅读是我不断前进的动力。对于上面所述,有什么新的观点或发现有什么错误,希望您能指出。
最后,附上个人常逛的社交平台:
知乎:https://www.zhihu.com/people/bi-an-yao-91/activities
csdn:https://blog.csdn.net/YaoDeBiAn
github: https://github.com/yaodebian我的邮箱:2801540120@qq.com or yaodebian@gmail.com
个人目前能力有限,并没有自主构建一个社区的能力,如有任何问题或想法与我沟通,请通过上述某个平台联系我,谢谢!!!