精读 express 系列——基础篇(2)
yaodebian opened this issue · comments
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 源码结构,简单理清它的运行原理)
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
个人目前能力有限,并没有自主构建一个社区的能力,如有任何问题或想法与我沟通,请通过上述某个平台联系我,谢谢!!!