常用链接
1.介绍
express
- 基于 Node.js 的 web 框架
- 用于快速搭建网站和应用,如博客、商场、聊天室、为前端提供 API
- 热门、健全、简单、少走弯路
- 简单路由系统
- 集成模版引擎
- 中间件系统
快速开始
npm init -y默认模式生成package.jsonnpm install --save express安装框架npm install -g nodemon方便调试,nodemon xxx启动应用
1 | var express = require('express') |
2 | |
3 | var app = express() |
4 | |
5 | app.get('/', function (req, res) { |
6 | res.send('this is homepage') |
7 | }) |
8 | |
9 | app.listen(3000) |
2.请求与响应
- 学会查看 官网 API 文档,最快最全,这个文档太清晰易懂了
- res.send([body])
- req.ip
1 | res.send(new Buffer('whoop')); |
2 | res.send({ some: 'json' }); |
3 | res.send('<p>some html</p>'); |
4 | res.status(404).send('Sorry, we cannot find that!'); |
5 | res.status(500).send({ error: 'something blew up' }); |
6 | |
7 | res.json({ user: 'tobi' }); |
8 | res.status(500).json({ error: 'message' }); |
9 | |
10 | req.ip |
11 | // => "127.0.0.1" |
12 | |
13 | // GET /search?q=tobi+ferret |
14 | req.query.q |
15 | // => "tobi ferret" |
16 | |
17 | // example.com/users?sort=desc |
18 | req.path |
19 | // => "/users" |
3.路由参数
- 路由参数是动态的
1 | // http://127.0.0.1:3000/profile/1/user/able |
2 | app.get('/profile/:id/user/:name', function (req, res) { |
3 | console.dir(req.params) // 显示属性 { id: '1', name: 'able' } |
4 | res.send("You requested " + req.params.id + req.params.name) |
5 | }) |
- 路由参数支持正则表达式
1 | app.get('/ab?cd', function (req, res) { |
2 | res.send('ab?cd') |
3 | }) |
4.查询字符串
- 文档 req.query
1 | // GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse |
2 | req.query.order |
3 | // => "desc" |
4 | |
5 | req.query.shoe.color |
6 | // => "blue" |
7 | |
8 | req.query.shoe.type |
9 | // => "converse" |
1 | // http://127.0.0.1:3000/?find=hot |
2 | app.get('/', function (req, res) { |
3 | console.dir(req.query) // => { find: 'hot' } |
4 | res.send('home page: ' + req.query.find) |
5 | }) |
5.POST请求和postman工具
使用 body-parser 包,处理 post 请求
- body-parser 文档
npm install body-parser --save安装- 查看文档,使用例子
postman 工具,用来图形化模拟浏览器发送各种请求
-
- HTTP/1.1 协议规定的 HTTP 请求方法有
OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT这几种 POST一般用来向服务端提交数据application/x-www-form-urlencoded普通表单提交multipart/form-data可以上传文件的表单
- HTTP/1.1 协议规定的 HTTP 请求方法有
1 | var bodyParser = require('body-parser') |
2 | // create application/json parser |
3 | var jsonParser = bodyParser.json() |
4 | // 使用中间件,在请求和响应中间处理 create application/x-www-form-urlencoded parser |
5 | var urlencodedParser = bodyParser.urlencoded({ extended: false }) |
6 | |
7 | app.post('/', urlencodedParser, function (req, res) { |
8 | console.dir(req.body) |
9 | res.send('ok') |
10 | }) |
11 | |
12 | app.post('/upload', jsonParser, function (req, res) { |
13 | console.dir(req.body) |
14 | res.send('ok') |
15 | }) |
6.上传文件
Multer 包 处理上传文件
Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files.
安装
npm install --save multer上传文件的表单需要指定
enctype="multipart/form-data"postman 上传文件,post body form-data
1 | // form.html |
2 | <form action="/upload" method="post" enctype="multipart/form-data"> |
3 | <h2>上传logo图片</h2> |
4 | <input type="file" name="logo"> |
5 | <input type="submit" value="提交"> |
6 | </form> |
1 | // 创建目录,上传文件 |
2 | var createFolder = function (folder) { |
3 | try { |
4 | fs.accessSync(folder); |
5 | } catch (e) { |
6 | fs.mkdirSync(folder); |
7 | } |
8 | }; |
9 | |
10 | var uploadFolder = './upload/'; |
11 | |
12 | createFolder(uploadFolder); |
13 | |
14 | var storage = multer.diskStorage({ |
15 | destination: function (req, file, cb) { |
16 | cb(null, uploadFolder); |
17 | }, |
18 | filename: function (req, file, cb) { |
19 | cb(null, file.originalname); |
20 | } |
21 | }); |
22 | var upload = multer({ storage: storage }); |
23 | |
24 | app.get('/form', function (req, res) { |
25 | var form = fs.readFileSync('./form.html', { encoding: "utf8" }) |
26 | res.send(form) |
27 | }) |
28 | |
29 | app.post('/upload', upload.single('logo'), function (req, res) { |
30 | console.dir(req.file); // 列出文件的所有属性 |
31 | res.send({ 'ret_code': 0 }) |
32 | }) |
7.模版引擎介绍
- 直接使用
res.sendFile(__dirname + '/form.html')响应网页
1 | app.get('/form', function (req, res) { |
2 | // var form = fs.readFileSync('./form.html', { encoding: "utf8" }) |
3 | // res.send(form) |
4 | res.sendFile(__dirname + '/form.html') |
5 | }) |
- 模版引擎 EJS
npm install ejs --save- 模版文件扩展名
.ejs - ejs 模版的Tags 特殊,非对称的,有前面和后面的,如
%> Plain ending tag
1 | app.get('/form/:name', function (req, res) { |
2 | var person = req.params.name |
3 | res.render('form', { person: person }) |
4 | }) |
5 | |
6 | // views/form.ejs |
7 | <h1><%= person %></h1> |
8 | // http://127.0.0.1:3000/form/able |
9 | // 输出 able |
- 将模板引擎用于 Express
- 在 Express 可以呈现模板文件之前,必须设置以下应用程序设置
- views:模板文件所在目录。例如:app.set(‘views’, ‘./views’) 默认
- view engine:要使用的模板引擎。例如:app.set(‘view engine’, ‘ejs’)
8.使用模版引擎
1 | app.get('/form/:name', function (req, res) { |
2 | // var person = req.params.name |
3 | var person = { age: 29, job: 'CEO', hobbies: ['eating', 'coding', 'finshing']} |
4 | res.render('form', { person: person }) |
5 | }) |
6 | |
7 | app.get('/about', function (req, res) { |
8 | // var person = req.params.name |
9 | res.render('about') |
10 | }) |
1 | <%- include('particals/header.ejs') -%> // 引用模版 |
2 | <h1><%= person %></h1> |
3 | <h1><%= person.age %></h1> |
4 | <h2>hobbies</h2> |
5 | <ul> //遍历数组 |
6 | <% person.hobbies.forEach(function(item){ %> |
7 | <li> |
8 | <%= item %> |
9 | </li> |
10 | <% }) %> |
11 | </ul> |
9.中间件介绍
- 中间件 (middleware)
- Express 是一个路由和中间件 Web 框架
- Express 应用程序基本上是一系列中间件函数调用
- 中间件介于 请求对象 (req)、响应对象 (res) 中间
- 可以有多个中间件
- 下一个中间件函数通常由名为 next 的变量来表示
- 如果当前中间件函数没有结束请求/响应循环那么它必须调用 next(),以将控制权传递给下一个中间件函数。否则,请求将保持挂起状态。
- 中间件作用
- 对请求和响应对象进行更改
- 结束请求或响应循环
- 调用堆栈中的下一个中间件函数
1 | // 没有路径的中间件函数, 每次收到请求时执行该函数。 |
2 | app.use(function (req, res, next) { |
3 | console.log('first middleware') |
4 | next() // 没有响应请求,需要将控制权传递给下一个中间件函数 |
5 | console.log('first middleware after next') |
6 | }) |
7 | |
8 | // 安装在某个路径的中间件函数 |
9 | app.use('/m', function (req, res, next) { |
10 | console.log('second middleware') |
11 | res.send('ok') |
12 | }) |
13 | |
14 | // app.get('/m', function (req, res, next) { |
15 | // res.send('ok') |
16 | // }) |
- 内置中间件
- Express 中唯一内置的中间件函数是 express.static
- 负责提供 Express 应用程序的静态资源
app.use(express.static('public'));指定静态资源根目录app.use('static', express.static('public'));前缀目录static/a.png
10.路由中间件
- 路由器层中间件绑定到 express.Router() 的实例
- 分离路由到子文件目录中,最上次只调用,总分路由
1 | // server.js |
2 | var indexRouter = require('./routes/index') |
3 | var usersRouter = require('./routes/users') |
4 | |
5 | app.use('/', indexRouter) |
6 | app.use('/users', usersRouter) |
7 | |
8 | // users.js |
9 | var express = require('express') |
10 | |
11 | var router = express.Router() |
12 | // 这里注意,因为前面路由匹配到/users了,这里直接时根即可,二级目录 |
13 | router.get('/', function (req, res, next) { |
14 | res.send('users') |
15 | }) |
16 | |
17 | module.exports = router |
11.项目实践 part 1 项目搭建
- express-todolist 实践项目
npm init -y初始化 package.jsonnpm install --save express body-parser ejs安装包
12.项目实践 part 2 Controller
- 新建
controllers文件夹,单独存放控制器
1 | //app.js |
2 | var express = require('express') |
3 | var todoController = require('./controllers/todoController') |
4 | |
5 | var app = express() |
6 | |
7 | app.set('view engine', 'ejs') |
8 | |
9 | // 指定public目录下为静态文件根目录 |
10 | app.use(express.static('public')) |
11 | |
12 | todoController(app) |
13 | |
14 | app.listen(3000) |
15 | |
16 | console.log('listening to port 3000') |
17 | |
18 | // todoController.js |
19 | module.exports = function (app) { |
20 | app.get('/todo', function (req, res) { |
21 | }) |
22 | |
23 | app.post('/todo', function (req, res) { |
24 | }) |
25 | |
26 | app.delete('/todo', function (req, res) { |
27 | }) |
28 | } |
13.项目实践 part 3 实现页面
新建
views文件夹,存放模版页面,todo.ejs使用 BootCDN 在线免费 jQuery 库
https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js
14.项目实践 part 4 实现功能
body-parser处理 post 请求ajax异步处理提交和删除
1 | // 显示添加表单和取出内容 |
2 | <div id="todo-table"> |
3 | <form action=""> |
4 | <input type="text" name="item" placeholder="Add new item..." required /> |
5 | <button type="submit">ADD Item</button> |
6 | </form> |
7 | <ul> |
8 | <% todos.forEach(function (todo) { %> |
9 | <li><%= todo.item %></li> |
10 | <% }) %> |
11 | </ul> |
12 | </div> |
1 | var bodyParser = require('body-parser') |
2 | var urlencodeParser = bodyParser.urlencoded({ extended: false}) |
3 | var data = [{item: 'get milk'}, {item: 'walk dog'}, {item: 'coding a'}] |
4 | |
5 | module.exports = function (app) { |
6 | app.get('/todo', function (req, res) { |
7 | res.render('todo', { todos: data }) |
8 | }) |
9 | |
10 | app.post('/todo', urlencodeParser, function (req, res) { |
11 | data.push(req.body) |
12 | res.json(data) // 回复结束响应,可以回复其它的 |
13 | }) |
14 | |
15 | app.delete('/todo/:item', function (req, res) { |
16 | data = data.filter(function (todo) { // 返回为true的内容 |
17 | return todo.item.replace(/ /g, "-") !== req.params.item |
18 | }) |
19 | res.json(data) |
20 | console.log(data) |
21 | }) |
22 | } |
1 | // ajax 处理点击提交 和 删除,异步处理 |
2 | $(document).ready(function() { |
3 | |
4 | $('form').on('submit', function(event) { |
5 | event.preventDefault(); |
6 | var item = $('form input'); |
7 | var todo = { item: item.val().trim() }; |
8 | |
9 | $.ajax({ |
10 | type: 'POST', |
11 | url: '/todo', |
12 | data: todo, |
13 | success: function(data) { |
14 | //do something with the data via front-end framework |
15 | location.reload(); |
16 | } |
17 | }); |
18 | |
19 | return false; |
20 | |
21 | }); |
22 | |
23 | $('li').on('click', function() { |
24 | var item = $(this).text().trim().replace(/ /g, "-"); |
25 | $.ajax({ |
26 | type: 'DELETE', |
27 | url: '/todo/' + item, |
28 | success: function(data) { |
29 | //do something with the data via front-end framework |
30 | location.reload(); |
31 | } |
32 | }); |
33 | }); |
34 | }); |
15.项目实践 part 5 MongoDB 和 mLab
使用 MongoDB 持久化数据
- nosql 非关系型的数据库,没有行列的概念,存储的 json 格式数据,用js很方便读取
- MongoDB 概念解析
- collection 数据库表/集合
- document 数据记录行/文档
- primary key 主键,MongoDB自动将_id字段设置为主键
使用线上免费 MongoDB 数据库 mLab
- Database-as-a-Service features
- MongoDB on AWS, Azure, or Google. It’s this easy.
- 注册,创建数据库,创建数据库用户
- shell 连接
mongo ds020208.mlab.com:20208/todos -u <dbuser> -p <dbpassword> - URI
mongodb://<dbuser>:<dbpassword>@ds020208.mlab.com:20208/todos
16.项目实践 part 6 Mongoose
- mongoose 用来操作数据库
- a MongoDB object modeling tool designed to work in an asynchronous environment.
npm install mongoose --save- 安装,连接,定义 Schema、model ,规定数据类型一致
1 | const mongoose = require('mongoose') |
2 | mongoose.connect('mongodb://able8:xx@ds020208.mlab.com:20208/todos') |
3 | |
4 | // Schema 模式,规定数据类型 |
5 | var todoSchema = new mongoose.Schema({ |
6 | item: String // 字段名,字符串 |
7 | }) |
8 | //对应数据库中的表 |
9 | var Todo = mongoose.model('Todo', todoSchema) |
10 | // 添加一条数据 |
11 | var itemOne = Todo({ item: 'buy flowers'}).save(function (err) { |
12 | if (err) throw err |
13 | console.log('item saved') |
14 | }) |
17.项目实践 part 7 保持数据到 MongoDB
- 操作数据,读取,添加,删除
- 实践测试 mLab 国内访问太慢了, 简单测试还可以
- 其他可选包 mongolass
1 | app.get('/todo', function (req, res) { |
2 | Todo.find({}, function (err, data) { |
3 | if (err) throw err |
4 | res.render('todo', { todos: data }) |
5 | }) |
6 | }) |
7 | |
8 | app.post('/todo', urlencodeParser, function (req, res) { |
9 | var itemOne = Todo(req.body).save(function (err, data) { |
10 | if (err) throw err |
11 | res.json(data) |
12 | }) |
13 | }) |
14 | |
15 | app.delete('/todo/:item', function (req, res) { |
16 | // data = data.filter(function (todo) { // 返回为true的内容 |
17 | // return todo.item.replace(/ /g, "-") !== req.params.item |
18 | // }) |
19 | Todo.find({item: req.params.item.replace(/ /g, '-')}).remove(function (err, data) { |
20 | if (err) throw err |
21 | res.json(data) |
22 | }) |
23 | }) |