Express框架
- 课程介绍
Ø Express介绍(了解)
Ø Express安装及使用(掌握)
Ø Express路由(掌握)
Ø response响应对象(掌握)
Ø request请求对象(掌握)
Ø 中间件(了解)
- Express介绍
Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。
Express 框架核心特性:
可以设置中间件来响应 HTTP 请求。
定义了路由表用于执行不同的 HTTP 请求动作。
(url = 资源) 映射
可以通过向模板传递参数来动态渲染 HTML 页面。 模板引擎
- Express使用
3.1. 简单使用(了解)
1、新建一个NodeJs项目文件夹
2、npm init 初始化项目配置文件(package.json 包描述文件)
package.json中
"scripts": {
"start":"node ./index" //命令
}
npm start 执行”start”后面的代码。
3、安装express
npm install express --save
4、编写一个app.js使用express
//导入express模块
var express = require("express");
//创建一个express应用
var app = express();
//处理"/"请求
app.get("/",function(req,res){
//响应输出“hello world”
res.send("Hello world");
});
//启动服务器监听3000端口
app.listen(3000,function(){
console.log("express app 启动成功。。。");
});
5、启动服务器
node app.js
6、浏览器访问
3.2. Express-generator(重点)
为了快速的创建express项目,express团队为使用者提供了项目快速生成工具,express-generator。
为了快速的创建express项目,express团队为使用者提供了项目快速生成工具,express-generator。
1、安装express-generator
npm i express-generator -g //全局安装
2、新建一个目录(或者找一个空目录)
F:\webproject (目录可以新建在任何位置,但最好不要中文路径)
3、通过命令创建express项目
express -e projecname (express代表在当前目录下面建立express项目 -e代表使用ejs模版引擎)
express webapp (代表在当前目录下面,新建一个webapp文件夹,然后在建立express项目)
项目结构:
bin : 执行文件,也是express项目启动文件。
public:公共的资源,浏览器可以直接访问的资源。(图片,js,css)
views:服务器端模块文件。
routes:路由处理器,处理浏览器发出不同url的处理程序。
/login function(){
//登录处理程序
}
app.js express应用的主文件,该文件主要用于整合其他第三方模块和配置express的系统参数。
4、安装依赖包
通过package.json
"dependencies": {
"body-parser": "~1.15.1",
"cookie-parser": "~1.4.3",
"debug": "~2.2.0",
"ejs": "~2.4.1",
"express": "~4.13.4",
"morgan": "~1.7.0",
"serve-favicon": "~2.3.0"
}
npm i
5、启动express
node app 需要设置监听端口
npm start
node ./bin/www
补充:nodemon:https://stackoverflow.com/questions/49001369/nodemonexpressjs-app-not-starting-clean-exit-waiting-for-changes-before-resta
6、浏览器访问
3.3. Express服务器项目结构说明
bin: 执行文件,也是express项目启动文件。
public: 公共的资源(nodejs不做处理),浏览器可以直接访问的资源,相当于静态网页的根目录,访问时不需加路径。(图片,js,css)
http://localhost:3000/test.html
http://localhost:3000/images/img.jpg
views: 服务器端模块或模板文件。
routes: 路由处理器,处理浏览器发出不同url的处理程序。动态网页的目录
----------------------------------------------------------------------------------
app.js 主模块文件,是总路由,分支路由写在routes目录下
package.json 包管理,依赖包
//引入系统和第三方模块
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//引入路由
var index = require('./routes/index');
var users = require('./routes/users');
var vipCenter=require("./routes/vip");
//实例化express框架
var app = express();
// view engine setup
//设置模板的默认目录
app.set('views', path.join(__dirname, 'views'));
//设置ejs为模板引擎
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
//中间件
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//设置静态目录为public
app.use(express.static(path.join(__dirname, 'public')));
//使用分路由
app.use('/', index);
app.use('/users', users);
app.use("/vip",vipCenter);
// catch 404 and forward to error handler
//404找不到
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
//错误
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
//导出模块
module.exports = app;
- Express路由(重点)
路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。
路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄(函数)组成,它的结构如下: app.METHOD(path, [callback...], callback), app 是 express 对象的一个实例, METHOD 是一个 HTTP 请求方法, path 是服务器上的路径, callback 是当路由匹配时要执行的函数。
4.1. 基础用法
var express = require('express');
var app = express();
//设置请求路径“/”对应的处理器
app.get('/', function(req, res) {
res.send('hello world');
});
4.2. 路由方法
路由与HTTP 请求方法(GET、POST)相关联。
为应用“/”路径定义的 GET 和 POST 请求:
// 处理get请求方式,超链接、浏览器地址栏直接访问
app.get('/', function (req, res) {
res.send('处理get请求');
});
// 处理post请求方式,表单提交
app.post('/', function (req, res) {
res.send('处理post请求');
});
app.all() 是一个特殊的路由方法,没有任何 HTTP 方法与其对应,它的作用是对于一个路径上的所有请求加载中间件。 all相当于既可以处理GET,也可以处理POST。
app.all('/, function (req, res, next) {
res.send('任意方式的请求');
});
4.3. Router(重点中的重点)
express.Router 类可以创建模块化(独立的)、可挂载的路由对象。Router 对象是一个完整的中间件和路由系统,因此常称其为一个 “mini-app”。
1、新建一个模块vip.js (express项目要求我们放到routes)
var express = require('express');
var router = express.Router();
// 定义模块的主页的路由
router.get('/', function(req, res) {
res.send('vip首页');
});
// 定义模块“/getScore”路径的路由
router.get('/getScore', function(req, res) {
res.send('vip积分');
});
module.exports = router;
2、app.js 使用
var vip = require('./vip);
...
app.use('/vip', vip); // 路径“/vip”使用vip路由模块,这个行为就是把“vip”模块挂载到“/vip”路径下面。
访问
[http://localhost:3000/vip](http://localhost:3000/vip)/ //vip首页
[http://localhost:3000/vip](http://localhost:3000/vip)/getScore //vip积分
- 响应对象(重点)
响应对象(res)的方法向客户端返回响应,终结请求响应的循环。如果在路由函数中一个方法也不调用,来自客户端的请求会一直挂起。
5.1. send方法(重点中的重点)
send(data) 可以返回任意类型数据。
res.send(new Buffer('whoop'));//流
res.send({ some: 'json' });// json数据
res.send('<p>some html</p>');//普通文本
//设置状态码,并且返回内容
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });
5.2.json方法
json(data) 返回json对象,一般针对ajax应用。
res.json(null);
res.json({ user: 'tobi' });
//设置状态码,并返回json数据
res.status(500).json({ error: 'message' });
5.3. jsonp方法
jsonp(data) 返回json对象,一般针对ajax的跨域访问。
res.jsonp(null);
res.jsonp({ user: 'tobi' });
//设置状态码,并返回json数据
res.status(500).jsonp({ error: 'message' });
5.4. render视图模板
ejs模板的使用
index.ejs模板
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<ul id="mainNav">
<li><a href="/">首页</a></li>
<li><a href="/news">新闻中心</a></li>
<li><a href="/vip">vip会员中心</a></li>
<li><a href="/users">用户注册</a></li>
</ul>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
</body>
</html>
index.js 路由
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' }); //将视图和数据合并后发送给客户端
});
module.exports = router;
5.5. download下载
//下载当前目录下面的xxx.doc文件,并且重命名为yyy.doc。
router.get('/down', function(req, res, next) {
res.download("./downTest.doc","express使用说明.doc")
});
5.6. redirect重定向
重定向到从指定的URL路径(浏览器地址变为设置的地址)
router.get('/it', function(req, res, next) {
res.redirect("http://www.baidu.cn");
});
5.7. 404报错页面制作
router.get('/err', function(req, res, next) {
//res.status(404).send("出错了:文件没有找到!");
res.status(404).render("error",{message:"很抱歉,您查看的宝贝不存在,可能已下架或者被转移。"});
});
error.ejs
<h1><%= message %></h1>
<p><img src="./images/err.png" /></p>
5.8. 完整api
res.app:同req.app一样
res.append():追加指定HTTP头
res.set()在res.append()后将重置之前设置的头
res.cookie(name,value [,option]):设置Cookie
opition: domain / expires / httpOnly / maxAge / path / secure / signed
- res.clearCookie():清除Cookie
npm install cookie
npm install cookie
var cookie=require("cookie");
res.cookie("username",username); // 设置cookie
req.cookies.名称 // 取值
res.clearCookie(‘名称’); // 清除指定名称的Cookie
手动清除cookie,设置》高级》清除浏览数据
router.get("/checkLogin",function(req,res,next){
var username=req.cookies.username;
if(username) {
res.send(true);
}
else{
res.send(false);
}
});
res.download():传送指定路径的文件
res.get():返回指定的HTTP头
res.json():传送JSON响应
res.jsonp():传送JSONP响应
res.location():只设置响应的Location HTTP头,不设置状态码或者close response
res.redirect():设置响应的Location HTTP头,并且设置状态码302
res.send():传送HTTP响应
res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
res.set():设置HTTP头,传入object可以一次设置多个头
res.status():设置HTTP状态码
res.type():设置Content-Type的MIME类型
请求对象(重点)
req(request)对象包含了数一次请求中的所有据(http头信息、请求参数...)
6.1. 获取浏览器地址栏中的参数(重点中的重点)
语法: req.query.参数名;
比如:http://localhost:3000/user?name=007
req.query.name;
搜索功能
search.html?keywords=笔记本电脑&catetype=it数码
router.get('/search.html', function(req, res, next) {
var keywords=req.query.keywords;
var catetype=req.query.catetype;
res.json({"关键词":keywords,"类别":catetype});
});
6.2. 获取表单提交的值(重点中的重点)
Post提交 req.body.参数名
Get提交 req.query.参数名;
login.html public静态文件
<form action="/loginPost" method="post">
<p>用户账号 <input type="text" name="username" /></p>
<p>登录密码 <input type="password" name="pwd" /></p>
<p><input type="submit" value="Post登录" /> </p>
</form>
<hr/>
<form action="/loginGet" method="get">
<p>用户账号 <input type="text" name="username" /></p>
<p>登录密码 <input type="password" name="pwd" /></p>
<p><input type="submit" value="Get登录" /> </p>
</form>
路由文件
router.get('/loginGet', function(req, res, next) {
var username=req.query.username;
var pwd=req.query.pwd;
res.json({"账号":username,"密码":pwd});
});
router.post('/loginPost', function(req, res, next) {
var username=req.body.username;
var pwd=req.body.pwd;
res.json({"账号":username,"密码":pwd});
});
6.3. 获取路由中的参数parameters
京东的产品地址:https://item.jd.com/5268701.html
/product/9999
router.get("/product/:id",function(req,res){
var productID=req.params.id;
res.send("产品的编号是:"+productID);
});
parameter [pəˈræmɪtɚ] params [pəˈræms]
伪静态: 看起来是一个静态文件,但其实是动态的。好处可以方便搜索引擎收录
6.4. 获取ip地址
router.get('/home', function(req, res, next) {
res.send("<h1>我是首页homepage!!!</h1><p>你的ip地址是:"+req.hostname+"_"+req.ip+"</p>");
});
6.5. 完整api
req.app:当callback为外部文件时,用req.app访问express的实例
req.baseUrl:获取路由当前安装的URL路径
req.body / req.cookies:获得「请求主体」/ Cookies
req.fresh / req.stale:判断请求是否还「新鲜」
req.hostname / req.ip:获取主机名和IP地址
req.originalUrl:获取原始请求URL
req.params:获取路由的parameters
req.path:获取请求路径
req.protocol:获取协议类型
req.query:获取URL的查询参数串
req.route:获取当前匹配的路由
req.subdomains:获取子域名
req.accpets():检查请求的Accept头的请求类型
req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages
req.get():获取指定的HTTP请求头
req.is():判断请求头Content-Type的MIME类型
- 中间件(了解)
Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。
7.1. 中间件到底是什么
中间件(Middleware)本质就是一个函数,它可以访问请求对象(request object), 响应对象(response object), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。(next 尾函数,执行下一个任务)
中间件的功能包括:
执行任何代码。
修改请求和响应对象。
终结请求-响应循环。
调用堆栈中的下一个中间件。
如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。
7.2. 应用级中间件
应用级中间件绑定到 app 对象 使用 app.use() 和 app.METHOD(), 其中, METHOD 是需要处理的 HTTP 请求的方法,例如 GET, PUT, POST 等等,全部小写。
//最简单的中间件
app.js
var express = require('express');
var app = express();
…………………………. ………………………….
/*
* 中间件:
* 1. 中间件是一个函数
* 2. 中间件可以访问请求对象和响应对象
* 3. 可以阻止请求继续执行,如果不阻止,可以调用尾函数 next()
*
* 尾函数next:
* 1. 在一个中间件中执行尾函数,就可以调用下一个中间件
* 2. 如果不用调用尾函数,就阻止执行
* 3. 在尾函数后面的代码会执行,并且是在尾函数调起的下一个中间件结束后才执行
*/
app.use(function(req,res,next){
console.log('111');
next();
console.log('222');
});
app.use(function(req,res,next){
console.log('333');
next();
console.log('444');
});
…………………………. ………………………….
module.exports = app;
7.3. 内置中间件
Express中只为我们提供了唯一一个中间件,其他的中间件需要安装。
下面的例子使用了 express.static中间件,其中的 options 对象经过了精心的设计。
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}}
app.use(express.static('public', options));
每个应用可有多个静态目录。
app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));
app.use(logger('dev')); //控制台日志显示的中间件
app.use(express.static(path.join(__dirname, 'public'))); //静态资源目录的中间件
7.4. 第三方中间件
通过使用第三方中间件从而为 Express 应用增加更多功能。
安装所需功能的 node 模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。
Multer 翻译文档https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md
文件上传中间件的使用
fileUpload.html 静态页面
fileUpload.html 静态页面
<form action="/upload" method="post" enctype="multipart/form-data">
<h2>图片上传</h2>
<input type="file" name="imgUpload">
<input type="submit" value="上传">
</form>
index.js 路由
/*
* npm i multer --save
*
前端准备工作:
1、需要一个表单,表单里面必须有一个文件域
2、必须给form表单指定enctype="multipart/form-data" 属性。
3、提交按钮类型为submit。
后端:接收请求
1:前端请求表单页面http://127.0.0.1/upload/
2:渲染模板,不需加载额外的数据。
教程:
http://blog.csdn.net/CatieCarter/article/details/77841208
https://github.com/expressjs/multer
*/
//引入文件模块
var fs = require("fs");
//引入上传中间件模块
var multer = require('multer');
//初始化上传目录,自定义本地保存的路径
//var upload = multer({ dest: './files/' }); //使用storage时不需要单独制定目录,storage中有目录设置
var uploadFolder='./public/files/'; //放入静态资源目录才能正常显示
// 通过storage的 filename 属性定制上传文件名称
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, uploadFolder); // 保存的路径,备注:需要自己创建如果不存在会报错
},
filename: function (req, file, cb) {
//将保存文件名设置为 前缀+时间戳+文件扩展名
var extName=file.originalname.substring(file.originalname.lastIndexOf(".")); //.jpg
cb(null, file.fieldname + '_' + new Date().getTime() + extName);
}
});
// 通过 storage 选项来对 上传行为 进行定制化
var upload = multer({ storage: storage });
//文件上传的路由,upload.single("imgUpload")指定单个文件上传,上传框的名称为imgUpload
router.post('/upload',upload.single("imgUpload"), function(req, res, next) {
var fileInfo = req.file; //multer会将文件的信息写到 req.file上
console.log('文件类型:', fileInfo.mimetype);
console.log('原始文件名:', fileInfo.originalname);
console.log('文件大小:', fileInfo.size);
console.log('文件保存路径:', fileInfo.path);
//渲染图片显示的模板,直接获取文件存放的地址,显示时不需要public目录
var filepath=fileInfo.path.toString().replace("public","");
res.render("imgFileList.ejs",{imgShow: filepath});
//直接显示出来
res.set({"Content-Type":"text/html"});
res.send("<img src='"+fileInfo.path.toString().replace("public","")+"' />");
});
imgFileList.ejs 图片显示模板
<body>
<h1>图片上传展示</h1>
<p><img src="<%= imgShow%>" /></p>
</body>
- 课程总结
8.1. 重点
安装 express
express的路由编写
请求对象
响应对象
8.2. 难点
路由编写
中间件
8.3. 如何掌握?
此技能通过使用升级。
将常见的用法截图保存到文件夹中,时常回顾。
8.4. 排错技巧(技巧)
console.log()方法。
作业
作业难度:☆☆☆
1、在自己的电脑上安装exress框架
2、如何获取GET和POST方式传值,分别使用什么方法。
3、编写路由实现一个简易的企业网站基本结构,根据不同链接路径响应不同的内容。
首页 | 新闻中心 | 产品展示 | 客户留言 | 关于我们 | 联系我们 | 官方商城
- 面试题
- 网络服务器的工作原理
- 扩展知识或课外阅读推荐(可选)
11.1. 扩展知识
使用 express-generator 创建的基本框架中各个目录的作用,以及静态目录
【补充】 cookie
由于HTTP是无状态协议,无法识别两次请求之间的关系,为了识别用户身份使用cookie技术。cookie技术是一向由服务器端设置数据,存储在客户端浏览器缓存中的一项技术。
只要服务器向浏览器设置了cookie,每一次浏览器发起请求时,都会自动携带这些cookie数据去访问服务器。服务器可以接收到数据并识别用户身份。
//设置新的cookie
res.cookie('名称','值');
//修改cookie
res.cookie('名称','新的值');
//删除cookie
res.clearCookie('名称');
//获取查询使用cookie
req.cookies.名称;
req.cookies.名称;
npm i --save nodemon
nodemon appname