├── .gitignore ├── README.md ├── SUMMARY.md ├── assets └── first-view.png ├── book.json ├── examples ├── 2016.11.07-advanced-express-multer │ ├── .gitignore │ ├── app.js │ ├── form.html │ ├── package.json │ ├── upload-custom-filename │ │ ├── app.js │ │ └── form.html │ ├── upload-get-file-info │ │ ├── app.js │ │ └── form.html │ ├── upload-multi │ │ ├── app.js │ │ └── form.html │ └── upload-single │ │ ├── app.js │ │ └── form.html ├── 2016.11.08-server-render │ └── app.js ├── getting-started │ ├── first-middleware.js │ ├── first-router.js │ ├── first-view.js │ └── views │ │ └── index.ejs ├── most-used-config │ ├── README.md │ ├── cookie.js │ ├── log-to-file.js │ ├── log.js │ └── logs │ │ └── access.log └── package.json ├── 入门.md ├── 常用 ├── README.md ├── cookie解析.md ├── 日志.md ├── 模板.md ├── 请求参数解析.md └── 路由拆分.md ├── 第一个demo.md ├── 第一个中间件.md ├── 第一个模板.md ├── 第一个路由.md ├── 进阶 ├── README.md ├── 会话.md ├── 会话管理.md ├── 加密.md ├── 基于muter的文件上传.md ├── 服务端页面渲染.md ├── 生产环境部署.md ├── 编写中间件.md ├── 编写模板引擎.md ├── 调试.md ├── 资源压缩.md ├── 进程管理.md └── 错误处理.md └── 项目目录简介.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Express学习笔记 2 | 3 | Express使用笔记by @[程序猿小卡 ](https://github.com/chyingp) 本书完整目录请[点击这里](SUMMARY.md) 4 | 5 | Express可以说是当前最流行的web应用开发框架,从github的关注数和npm每日的下载量就可以看出。 6 | 7 | 从设计上来看,Express同时具备以下特点:1、性能高 2、可扩展性强 3、学习成本低 8 | 9 | 对于初接触服务端开发的Node开发者,第3点显得尤为重要。 10 | 11 | Express的[官方文档](http://expressjs.com/en/4x/api.html)已经比较完善了,对于有一定Node基础的同学,建议直接看官方文档。 12 | 13 | 本书从一个Express学习者的角度,记录下一些学习的心得。包括 14 | 15 | * 入门:Express的安装、项目初始化、路由/模板/中间件的介绍和入门使用。 16 | * 进阶:常用配置、中间件的使用等,如cookie解析、请求参数解析、中间件编写、模板引擎编写、进程管理、调试等。 17 | * 实战:实际部署到生产环境的步骤、注意事项、常见问题处理等。 18 | 19 | 如有内容上建议,或者错误的校正,欢迎github提issue :) 20 | 21 | ## 关于作者 22 | 23 | 程序猿小卡,前腾讯IMWEB团队成员,阿里云栖社区专家认证博主。口号是:专注前端三十年。 24 | 25 | [github](https://github.com/chyingp) / [新浪微博](http://weibo.com/chyingp?is_all=1) / [知乎](https://www.zhihu.com/people/chen-ying-ping-57) / [博客园](http://chyingp.cnblogs.com/) / [Segmentfault](https://segmentfault.com/u/chyingp) / [云栖社区](https://yq.aliyun.com/users/1970729537231450?spm=5176.100240.searchblog.12.xDc8pM&do=login) / [站酷](http://www.zcool.com.cn/u/346408) 26 | 27 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [入门](入门.md) 5 | 6 | * [demo项目初始化(ok)](第一个demo.md) 7 | * [项目目录简介(ok)](项目目录简介.md) 8 | * [第一个路由(ok)](第一个路由.md) 9 | * [第一个模板(ok)](第一个模板.md) 10 | * [第一个中间件(ok)](第一个中间件.md) 11 | 12 | * [常用配置](常用/README.md) 13 | 14 | * [日志](常用/日志.md) 15 | * [模板](常用/模板.md) 16 | * [请求参数解析](常用/请求参数解析.md) 17 | * [cookie解析](常用/cookie解析.md) 18 | * [路由拆分](常用/路由拆分.md) 19 | 20 | * [进阶使用](进阶/README.md) 21 | 22 | * [基于muter的文件上传](/进阶/基于muter的文件上传.md) 23 | * [加密](进阶/加密.md) 24 | * [资源压缩](进阶/资源压缩.md) 25 | * [会话](进阶/会话.md) 26 | * [错误处理](进阶/错误处理.md) 27 | * [进程管理](进阶/进程管理.md) 28 | * [编写中间件](进阶/编写中间件.md) 29 | * [编写模板引擎](进阶/编写模板引擎.md) 30 | * [生产环境部署](进阶/生产环境部署.md) 31 | 32 | 33 | -------------------------------------------------------------------------------- /assets/first-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/assets/first-view.png -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "github-buttons" 4 | ], 5 | "pluginsConfig": { 6 | "github-buttons": { 7 | "repo": "chyingp/Express-learning-guide", 8 | "types": [ 9 | "star", 10 | "watch" 11 | ] 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /examples/2016.11.07-advanced-express-multer/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | upload/ -------------------------------------------------------------------------------- /examples/2016.11.07-advanced-express-multer/app.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var express = require('express'); 3 | var multer = require('multer') 4 | 5 | var app = express(); 6 | var uploadSingle = multer({ dest: 'upload-single/' }); 7 | var uploadMulti = multer({ dest: 'upload-multi/' }); 8 | 9 | // 单图上传 10 | app.post('/upload-single', uploadSingle.single('logo'), function(req, res, next){ 11 | res.send({ret_code: '0'}); 12 | }); 13 | 14 | // 多图上传 15 | app.post('/upload-multi', uploadMulti.array('logos', 2), function(req, res, next){ 16 | res.send({ret_code: '0'}); 17 | }); 18 | 19 | app.get('/form', function(req, res, next){ 20 | var form = fs.readFileSync('./form.html', {encoding: 'utf8'}); 21 | res.send(form); 22 | }); 23 | 24 | app.listen(3000); 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/2016.11.07-advanced-express-multer/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |模板就是这么简单
10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/most-used-config/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/examples/most-used-config/README.md -------------------------------------------------------------------------------- /examples/most-used-config/cookie.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var cookieParser = require('cookie-parser'); 3 | var app = express(); 4 | 5 | app.use(cookieParser()); 6 | 7 | app.get('/', function (req, res, next) { 8 | 9 | if(req.headers.cookie){ 10 | console.log('解析前的cookie:' + req.headers.cookie); 11 | } 12 | 13 | var visit = req.cookies.visit || 0; // 讀取cookie 14 | 15 | res.cookie('visit', ++visit, {maxAge: 60000}); // 設置cookie 16 | 17 | res.set('Content-Type', 'text/html; charset=utf-8'); 18 | 19 | res.send( '您已訪問:' + visit + '次' ); 20 | }) 21 | 22 | app.listen(3000) -------------------------------------------------------------------------------- /examples/most-used-config/log-to-file.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var fs = require('fs') 3 | var morgan = require('morgan') 4 | var path = require('path') 5 | 6 | var app = express() 7 | 8 | // create a write stream (in append mode) 9 | var accessLogStream = fs.createWriteStream(path.join(__dirname, 'logs/access.log'), {flags: 'a'}) 10 | 11 | // setup the logger 12 | app.use(morgan('combined', {stream: accessLogStream})) 13 | 14 | app.get('/', function (req, res) { 15 | res.send('hello, world!') 16 | }) 17 | 18 | app.listen(3000) -------------------------------------------------------------------------------- /examples/most-used-config/log.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var morgan = require('morgan') 3 | var app = express() 4 | 5 | app.use(morgan('combined')) 6 | 7 | app.get('/', function (req, res) { 8 | res.send('hello, world!') 9 | }); 10 | 11 | app.listen(3000); 12 | -------------------------------------------------------------------------------- /examples/most-used-config/logs/access.log: -------------------------------------------------------------------------------- 1 | ::ffff:127.0.0.1 - - [02/Nov/2016:05:10:40 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" 2 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cookie-parser": "^1.4.3", 14 | "ejs": "^2.5.2", 15 | "express": "^4.14.0", 16 | "morgan": "^1.7.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /入门.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/入门.md -------------------------------------------------------------------------------- /常用/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/常用/README.md -------------------------------------------------------------------------------- /常用/cookie解析.md: -------------------------------------------------------------------------------- 1 | ## 为什么需要cookie-parser 2 | 3 | 我们知道,在nodejs里面,我们想要读取、设置cookie,可以分别通过如下方式: 4 | 5 | 1、读取cookie:可以通过 **req.headers.cookie** 来获取HTTP请求携带的cookie。大概是类似下面的字符串。 6 | 7 | ``` 8 | uid=23ddjl3k2k; visit=3; 9 | ``` 10 | 11 | 2、设置cookie:通过 **Set-Cookie** 首部来达到设置cookie的目的。 12 | 13 | ```javascript 14 | res.setHeader('Set-Cookie', 'visit=3; Max-Age=60; Path=/; Expires=Wed, 02 Nov 2016 12:02:58 GMT'); 15 | ``` 16 | 17 | **问题在哪呢**? 18 | 19 | 很明显,无论是读取分析cookie的值,还是设置cookie,都不够方便。 20 | 21 | 在express里,我们可以通过 cookie-parser 来方便的完成cookie的读、写。 22 | 23 | ## cookie-parser中间件使用 24 | 25 | 使用很简单,demo如下。也可以看[官方文档说明](https://github.com/expressjs/cookie-parser)。 26 | 27 | * 读取cookie值:req.cookies.visit 28 | * 设置cookie值:res.cookie('visit', '3') 29 | 30 | ```javascript 31 | var express = require('express'); 32 | var cookieParser = require('cookie-parser'); 33 | var app = express(); 34 | 35 | app.use(cookieParser()); 36 | 37 | app.get('/', function (req, res, next) { 38 | 39 | if(req.headers.cookie){ 40 | console.log('解析前的cookie:' + req.headers.cookie); 41 | } 42 | 43 | var visit = req.cookies.visit || 0; // 讀取cookie 44 | 45 | res.cookie('visit', ++visit, {maxAge: 60000}); // 設置cookie 46 | 47 | res.set('Content-Type', 'text/html; charset=utf-8'); 48 | 49 | res.send( '您已訪問:' + visit + '次' ); 50 | }) 51 | 52 | app.listen(3000) 53 | 54 | ``` 55 | 56 | ## 进一步使用 57 | 58 | 至于cookie的过期时间、path、domain等设置,可以参考官方文档。 59 | 60 | 在后续文档 会话管理 里面,还会进一步接触 cookie-parser 的使用。 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /常用/日志.md: -------------------------------------------------------------------------------- 1 | ## morgan 2 | 3 | express脚手架默认用的日志中间件是**morgan。morgan**本身使用不复杂,官方文档也写的挺清晰了,这里就不打算写得太详细。 4 | 5 | ## 安装 6 | 7 | ``` 8 | npm install --save morgan 9 | ``` 10 | 11 | ## 使用 12 | 13 | 使用配置非常简单,就两行代码。(代码) 14 | 15 | ``` 16 | var express = require('express') 17 | var morgan = require('morgan') 18 | 19 | var app = express() 20 | 21 | app.use(morgan('combined')) 22 | 23 | app.get('/', function (req, res) { 24 | res.send('hello, world!') 25 | }); 26 | 27 | app.listen(3000); 28 | ``` 29 | 30 | 运行服务,在浏览器里访问 [http:\/\/127.0.0.1:3000](http://127.0.0.1:3000),就可以在控制台下看到如下日志。 31 | 32 | ```bash 33 | ➜ most-used-config git:(master) ✗ node log.js 34 | ::ffff:127.0.0.1 - - [02/Nov/2016:05:04:32 +0000] "GET / HTTP/1.1" 200 13 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" 35 | ``` 36 | 37 | ## 把日志写到日志文件 38 | 39 | 同样非常简单,修改下配置即可。然后,用户的访问日志就不再是打印到控制台,而是写到本地文件 access.log 了。 40 | 41 | ```javascript 42 | var fs = require('fs'); 43 | var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'}) 44 | app.use(morgan('combined', {stream: accessLogStream})) 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /常用/模板.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/常用/模板.md -------------------------------------------------------------------------------- /常用/请求参数解析.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/常用/请求参数解析.md -------------------------------------------------------------------------------- /常用/路由拆分.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/常用/路由拆分.md -------------------------------------------------------------------------------- /第一个demo.md: -------------------------------------------------------------------------------- 1 | ## 安装脚手架工具 2 | 3 | 对于初学者来说,建议安装脚手架工具`express-generator`。 4 | 5 | ``` 6 | npm install -g express-generator 7 | ``` 8 | 9 | 运行完上面命令,就会在本地安装\`express\`命令,可以用它来初始化项目骨架。 10 | 11 | ## 创建项目 12 | 13 | 比如,创建项目**demo**。参数说明 14 | 15 | * `demo`:项目所在目录。 16 | * `-e`:初始化的项目,用ejs做为模板引擎。 17 | 18 | 19 | ``` 20 | ➜ /tmp express -e demo 21 | 22 | create : demo 23 | create : demo/package.json 24 | create : demo/app.js 25 | create : demo/public 26 | create : demo/public/javascripts 27 | create : demo/routes 28 | create : demo/routes/index.js 29 | create : demo/routes/users.js 30 | create : demo/public/stylesheets 31 | create : demo/public/stylesheets/style.css 32 | create : demo/views 33 | create : demo/views/index.ejs 34 | create : demo/views/error.ejs 35 | create : demo/public/images 36 | create : demo/bin 37 | create : demo/bin/www 38 | 39 | install dependencies: 40 | $ cd demo && npm install 41 | 42 | run the app: 43 | $ DEBUG=demo:* npm start 44 | ``` 45 | 46 | ## 安装项目依赖 47 | 48 | 安装指示安装依赖 49 | 50 | ``` 51 | ➜ /tmp cd demo 52 | ➜ demo npm install 53 | ``` 54 | 55 | ## 启动项目 56 | 57 | 通过下面命令启动项目。默认监听端口为3000. 58 | 59 | ``` 60 | ➜ demo npm start 61 | 62 | > demo@0.0.0 start /private/tmp/demo 63 | > node ./bin/www 64 | ``` 65 | 66 | 试下在浏览器里访问 http://127.0.0.1:3000 恭喜你,迈出成功第一步。 67 | 68 | -------------------------------------------------------------------------------- /第一个中间件.md: -------------------------------------------------------------------------------- 1 | ## 中间件长什么样子 2 | 3 | 在express中,中间件是非常重要的概念。一个请求,从浏览器发起,到服务端返回,生命周期大概是下面这样子。 4 | 5 | > 浏览器发起请求 -> 服务端收到请求 -> 中间件A -> 中间件B -> ... -> 服务端返回 6 | 7 | 对pipeline有所了解的同学应该对上面的处理方式不陌生。 8 | 9 | 如果不了解也没关系,我们直接来看下,一个最简单中间件是什么样子的。 10 | 11 | * req:请求对象。可以从中获取请求相关信息,比如访问地址等。(浏览器 --> 服务器) 12 | 13 | * res:响应对象。可以向浏览器返回响应内容,比如返回HTML页面。(服务器 --> 浏览器) 14 | 15 | * next:一个函数。目前仅需要知道,next\(\) 被调用时,控制权就会从当前中间件,转移到下一个中间件。 16 | 17 | 18 | ```js 19 | function(req, res, next){ 20 | console.log('打印一些日志'); 21 | next(); 22 | } 23 | ``` 24 | 25 | 下面就看实际的例子 26 | 27 | ## 中间件的例子 28 | 29 | 看下面代码示例([代码](/examples/getting-started/first-middleware.js)),用户访问 \/hello 路径时,服务端先 1、打印日志 2、访问数据库 3、最后才返回网页。 30 | 31 | 这三个步骤,可以拆分成三个中间件,如下所示,非常简单。结构更清晰,同时方便拆分组合。 32 | 33 | 比如某一天,不想打印访问日志了,把第一个中间件删掉就行。 34 | 35 | ```js 36 | var express = require('express'); 37 | var app = express(); 38 | 39 | app.get('/hello', function(req, res, next){ 40 | console.log('打印访问日志'); 41 | next(); 42 | }); 43 | 44 | app.get('/hello', function(req, res, next){ 45 | console.log('假设我在访问数据库'); 46 | next(); 47 | }); 48 | 49 | app.get('/hello', function(req, res, next){ 50 | res.send('你好我是中间件!'); 51 | }); 52 | 53 | app.listen(3000); 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /第一个模板.md: -------------------------------------------------------------------------------- 1 | ## 添加模板 2 | 3 | 代码如下,模板引擎的配置语法、参数这里先不用关心,后面会详细进行介绍。 4 | 5 | 下面代码无非做了以下事情:([代码](/examples/getting-started/first-view.js)) 6 | 7 | 1. 声明项目用的模板引擎是ejs。 8 | 2. 添加路由,当用户访问 \/index 时,返回 views\/index 模板渲染出来的页面 9 | 3. 渲染模板时,传了点数据进去(标题) 10 | 11 | ```javascript 12 | var express = require('express'); 13 | var path = require('path'); 14 | var app = express(); 15 | 16 | // 模板引擎配置 17 | app.set('views', path.join(__dirname, 'views')); 18 | app.set('view engine', 'ejs'); 19 | 20 | // 返回模板渲染的页面 21 | app.get('/index', function(req, res, next){ 22 | res.render('index', { 23 | title: '程序猿小卡的第一个模板' 24 | }); 25 | }); 26 | 27 | app.listen(3000); 28 | ``` 29 | 30 | 模板如下:([代码](/examples/getting-started/views/index.ejs)) 31 | 32 | ```html 33 | 34 | 35 | 36 |模板就是这么简单
42 | 43 | 44 | 45 | ``` 46 | 47 | ## 运行代码查看效果 48 | 49 | ```bash 50 | node first-view.js 51 | ``` 52 | 53 | 浏览器里访问 [http:\/\/127.0.0.1:3000\/index](http://127.0.0.1:3000/index) 54 | 55 |  56 | 57 | -------------------------------------------------------------------------------- /第一个路由.md: -------------------------------------------------------------------------------- 1 | ## 添加路由 2 | 3 | express里添加路由规则相当简单。如下代码所示,一个路由规则就添加好了。代码参考[这里](/examples/getting-started/first-router.js)。 4 | 5 | ```javascript 6 | var express = require('express'); 7 | var app = express(); 8 | 9 | app.get('/hello', function(req, res, next){ 10 | res.send('hello world!'); 11 | }); 12 | 13 | app.listen(3000); 14 | ``` 15 | 16 | 启动服务,然后访问 [http:\/\/127.0.0.1\/hello,搞定。](http://127.0.0.1/hello,搞定。) 17 | 18 | -------------------------------------------------------------------------------- /进阶/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/README.md -------------------------------------------------------------------------------- /进阶/会话.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/会话.md -------------------------------------------------------------------------------- /进阶/会话管理.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/会话管理.md -------------------------------------------------------------------------------- /进阶/加密.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/加密.md -------------------------------------------------------------------------------- /进阶/基于muter的文件上传.md: -------------------------------------------------------------------------------- 1 | ## 概览 2 | 3 | 图片上传是web开发中经常用到的功能,node社区在这方面也有了相对完善的支持。 4 | 5 | 常用的开源组件有**multer**、**formidable**等,借助这两个开源组件,可以轻松搞定图片上传。 6 | 7 | 本文主要讲解以下内容,后续章节会对技术实现细节进行深入挖掘。本文所有例子均有代码示例,可在[这里](../examples/2016.11.07-advanced-express-multer/)查看。 8 | 9 | * 基础例子:借助express、multer实现单图、多图上传。 10 | * 常用API:获取上传的图片的信息。 11 | * 进阶使用:自定义保存的图片路径、名称。 12 | 13 | ## 环境初始化 14 | 15 | 非常简单,一行命令。 16 | 17 | ```bash 18 | npm install express multer multer --save 19 | ``` 20 | 21 | 每个示例下面,都有下面两个文件 22 | 23 | ```bash 24 | ➜ upload-custom-filename git:(master) ✗ tree -L 1 25 | . 26 | ├── app.js # 服务端代码,用来处理文件上传请求 27 | ├── form.html # 前端页面,用来上传文件 28 | ``` 29 | 30 | ## 基础例子:单图上传 31 | 32 | 完整示例代码请参考[这里](../examples/2016.11.07-advanced-express-multer/upload-single)。 33 | 34 | [app.js](../examples/2016.11.07-advanced-express-multer/upload-single/app.js)。 35 | 36 | ```javascript 37 | var fs = require('fs'); 38 | var express = require('express'); 39 | var multer = require('multer') 40 | 41 | var app = express(); 42 | var upload = multer({ dest: 'upload/' }); 43 | 44 | // 单图上传 45 | app.post('/upload', upload.single('logo'), function(req, res, next){ 46 | res.send({ret_code: '0'}); 47 | }); 48 | 49 | app.get('/form', function(req, res, next){ 50 | var form = fs.readFileSync('./form.html', {encoding: 'utf8'}); 51 | res.send(form); 52 | }); 53 | 54 | app.listen(3000); 55 | 56 | ``` 57 | 58 | 59 | [form.html](../examples/2016.11.07-advanced-express-multer/upload-single/form.html)。 60 | 61 | ```html 62 | 67 | ``` 68 | 69 | 运行服务。 70 | 71 | ```bash 72 | node app.js 73 | ``` 74 | 75 | 76 | 访问 http://127.0.0.1:3000/form ,选择图片,点击“提交”,done。然后,你就会看到 upload 目录下多了个图片。 77 | 78 | ## 基础例子:多图上传 79 | 80 | 完整示例代码请参考[这里](../examples/2016.11.07-advanced-express-multer/upload-multi)。 81 | 82 | 代码简直不能更简单,将前面的 upload.single('logo') 改成 upload.array('logo', 2) 就行。表示:同时支持2张图片上传,并且 name 属性为 logo。 83 | 84 | [app.js](../examples/2016.11.07-advanced-express-multer/upload-multi/app.js)。 85 | 86 | ```javascript 87 | var fs = require('fs'); 88 | var express = require('express'); 89 | var multer = require('multer') 90 | 91 | var app = express(); 92 | var upload = multer({ dest: 'upload/' }); 93 | 94 | // 多图上传 95 | app.post('/upload', upload.array('logo', 2), function(req, res, next){ 96 | res.send({ret_code: '0'}); 97 | }); 98 | 99 | app.get('/form', function(req, res, next){ 100 | var form = fs.readFileSync('./form.html', {encoding: 'utf8'}); 101 | res.send(form); 102 | }); 103 | 104 | app.listen(3000); 105 | 106 | 107 | ``` 108 | 109 | 110 | [form.html](../examples/2016.11.07-advanced-express-multer/upload-multi/form.html)。 111 | 112 | 113 | ```html 114 | 120 | ``` 121 | 122 | 同样的测试步骤,不赘述。 123 | 124 | ## 获取上传的图片的信息 125 | 126 | 完整示例代码请参考[这里](../examples/2016.11.07-advanced-express-multer/upload-get-file-info)。 127 | 128 | 很多时候,除了将图片保存在服务器外,我们还需要做很多其他事情,比如将图片的信息存到数据库里。 129 | 130 | 常用的信息比如原始文件名、文件类型、文件大小、本地保存路径等。借助multer,我们可以很方便的获取这些信息。 131 | 132 | 还是单文件上传的例子,此时,multer会将文件的信息写到 req.file 上,如下代码所示。 133 | 134 | 135 | [app.js](../examples/2016.11.07-advanced-express-multer/upload-get-file-info/app.js)。 136 | 137 | ```javascript 138 | var fs = require('fs'); 139 | var express = require('express'); 140 | var multer = require('multer') 141 | 142 | var app = express(); 143 | var upload = multer({ dest: 'upload/' }); 144 | 145 | // 单图上传 146 | app.post('/upload', upload.single('logo'), function(req, res, next){ 147 | var file = req.file; 148 | 149 | console.log('文件类型:%s', file.mimetype); 150 | console.log('原始文件名:%s', file.originalname); 151 | console.log('文件大小:%s', file.size); 152 | console.log('文件保存路径:%s', file.path); 153 | 154 | res.send({ret_code: '0'}); 155 | }); 156 | 157 | app.get('/form', function(req, res, next){ 158 | var form = fs.readFileSync('./form.html', {encoding: 'utf8'}); 159 | res.send(form); 160 | }); 161 | 162 | app.listen(3000); 163 | ``` 164 | 165 | 166 | [form.html](../examples/2016.11.07-advanced-express-multer/upload-get-file-info/form.html)。 167 | 168 | ```html 169 | 174 | ``` 175 | 176 | 启动服务,上传文件后,就会看到控制台下打印出的信息。 177 | 178 | ```bash 179 | 文件类型:image/png 180 | 原始文件名:1.png 181 | 文件大小:18379 182 | 文件保存路径:upload/b7e4bb22375695d92689e45b551873d9 183 | ``` 184 | 185 | 186 | ## 自定义文件上传路径、名称 187 | 188 | 有的时候,我们想要定制文件上传的路径、名称,multer也可以方便的实现。 189 | 190 | ### 自定义本地保存的路径 191 | 192 | 非常简单,比如我们想将文件上传到 my-upload 目录下,修改下 dest 配置项就行。 193 | 194 | ``` 195 | var upload = multer({ dest: 'upload/' }); 196 | ``` 197 | 198 | 在上面的配置下,所有资源都是保存在同个目录下。有时我们需要针对不同文件进行个性化设置,那么,可以参考下一小节的内容。 199 | 200 | ### 自定义本地保存的文件名 201 | 202 | 完整示例代码请参考[这里](../examples/2016.11.07-advanced-express-multer/upload-custom-filename)。 203 | 204 | 代码稍微长一点,单同样简单。multer 提供了 **storage** 这个参数来对资源保存的路径、文件名进行个性化设置。 205 | 206 | 使用注意事项如下: 207 | 208 | * destination:设置资源的保存路径。注意,如果没有这个配置项,默认会保存在 /tmp/uploads 下。此外,路径需要自己创建。 209 | * filename:设置资源保存在本地的文件名。 210 | 211 | [app.js](../examples/2016.11.07-advanced-express-multer/upload-custom-filename/app.js)。 212 | 213 | ``` 214 | var fs = require('fs'); 215 | var express = require('express'); 216 | var multer = require('multer') 217 | 218 | var app = express(); 219 | 220 | var createFolder = function(folder){ 221 | try{ 222 | fs.accessSync(folder); 223 | }catch(e){ 224 | fs.mkdirSync(folder); 225 | } 226 | }; 227 | 228 | var uploadFolder = './upload/'; 229 | 230 | createFolder(uploadFolder); 231 | 232 | // 通过 filename 属性定制 233 | var storage = multer.diskStorage({ 234 | destination: function (req, file, cb) { 235 | cb(null, uploadFolder); // 保存的路径,备注:需要自己创建 236 | }, 237 | filename: function (req, file, cb) { 238 | // 将保存文件名设置为 字段名 + 时间戳,比如 logo-1478521468943 239 | cb(null, file.fieldname + '-' + Date.now()); 240 | } 241 | }); 242 | 243 | // 通过 storage 选项来对 上传行为 进行定制化 244 | var upload = multer({ storage: storage }) 245 | 246 | // 单图上传 247 | app.post('/upload', upload.single('logo'), function(req, res, next){ 248 | var file = req.file; 249 | res.send({ret_code: '0'}); 250 | }); 251 | 252 | app.get('/form', function(req, res, next){ 253 | var form = fs.readFileSync('./form.html', {encoding: 'utf8'}); 254 | res.send(form); 255 | }); 256 | 257 | app.listen(3000); 258 | ``` 259 | 260 | [form.html](../examples/2016.11.07-advanced-express-multer/upload-custom-filename/form.html)。 261 | 262 | ```html 263 | 268 | ``` 269 | 270 | 测试步骤不赘述,访问一下就知道效果了。 271 | 272 | ## 写在后面 273 | 274 | 本文对multer的基础用法进行了介绍,并未涉及过多原理性的东西。俗话说 **授人以渔不如授人以渔**,在后续的章节里,会对文件上传的细节进行挖掘,好让读者朋友对文件上传加深进一步的认识。 275 | 276 | ## 关于作者 277 | 278 | 程序猿小卡,前腾讯IMWEB团队成员,阿里云栖社区专家认证博主。口号是:专注前端三十年。 279 | 280 | [github](https://github.com/chyingp) / [新浪微博](http://weibo.com/chyingp?is_all=1) / [知乎](https://www.zhihu.com/people/chen-ying-ping-57) / [博客园](http://chyingp.cnblogs.com/) / [Segmentfault](https://segmentfault.com/u/chyingp) / [云栖社区](https://yq.aliyun.com/users/1970729537231450?spm=5176.100240.searchblog.12.xDc8pM&do=login) / [站酷](http://www.zcool.com.cn/u/346408) 281 | 282 | 283 | ## 相关链接 284 | 285 | multer官方文档:https://github.com/expressjs/multer 286 | -------------------------------------------------------------------------------- /进阶/服务端页面渲染.md: -------------------------------------------------------------------------------- 1 | ## 服务端页面渲染 2 | 3 | ## 相关链接 -------------------------------------------------------------------------------- /进阶/生产环境部署.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/生产环境部署.md -------------------------------------------------------------------------------- /进阶/编写中间件.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/编写中间件.md -------------------------------------------------------------------------------- /进阶/编写模板引擎.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/编写模板引擎.md -------------------------------------------------------------------------------- /进阶/调试.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/调试.md -------------------------------------------------------------------------------- /进阶/资源压缩.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyingp/Express-learning-guide/ce4c875add8b3130be32a796da28676390ddefc1/进阶/资源压缩.md -------------------------------------------------------------------------------- /进阶/进程管理.md: -------------------------------------------------------------------------------- 1 | ## 为什么需要进程管理器 2 | 3 | 做过服务端开发的同学应该比较清楚,在生产环境运行一个web服务,并不是只是简单的把服务启动起来就可以。为了确保服务质量,至少需要完成下面事情: 4 | 5 | * 服务异常重启 6 | * 服务资源占用情况监控 7 | * 配置灵活更改(加自动重启生效) 8 | * 集群部署(性能相关) 9 | 10 | 这个时候,进程管理器显得非常重要。目前常用的node进程管理器有pm2、forever等。 11 | 12 | 笔者两者都用过,个人更喜欢pm2。下文就简单围绕pm2展开。更多更详尽的总结,可以参考笔者之前的总结文章[《PM2实用入门指南》](https://segmentfault.com/a/1190000006793571#articleHeader13)。 13 | 14 | ## pm2安装 15 | 16 | 方便起见,一般都采取全局安装。 17 | 18 | ```bash 19 | npm install -g pm2 20 | ``` 21 | 22 | ## 启动服务 23 | 24 | 假设我们通过 express 的脚手架初始化项目 25 | 26 | ```bash 27 | express demo 28 | ``` 29 | 30 | 然后,启动项目。-w 表示,当项目文件发生变化时,服务自动重启。 31 | 32 | 33 | ```bash 34 | ➜ demo pm2 start -w ./bin/www 35 | [PM2] Starting ./bin/www in fork_mode (1 instance) 36 | [PM2] Done. 37 | ┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐ 38 | │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ 39 | ├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤ 40 | │ www │ 0 │ fork │ 84743 │ online │ 0 │ 0s │ 14.969 MB │ disabled │ 41 | └──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘ 42 | Use `pm2 show