1. 课程介绍
◆ Express介绍(了解)
◆ Express安装及使用(掌握)
◆ Express路由(掌握)
◆ response响应对象(掌握)
◆ request请求对象(掌握)
◆ 中间件(了解)
2. Express介绍
Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。
Express 框架核心特性:
n 可以设置中间件来响应 HTTP 请求。
n 定义了路由表用于执行不同的 HTTP 请求动作。
(url = 资源) 映射
n 可以通过向模板传递参数来动态渲染 HTML 页面。 模板引擎
3. 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。
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
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;
4. 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/ //vip首页
http://localhost:3000/vip/getScore //vip积分
5. 响应对象(重点)
响应对象(res)的方法向客户端返回响应,终结请求响应的循环。如果在路由函数中一个方法也不调用,来自客户端的请求会一直挂起。
5.1. send方法(重点中的重点)
send(data) 可以返回任意类型数据。
res.send(new Buffer('whoop'));//流
res.send({ some: 'json' });// json数据
res.send('some html
');//普通文本
//设置状态码,并且返回内容
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模板
<%= title %>
<%= title %>
Welcome to <%= title %>
**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
<%= message %>
5.8. 完整api
1. res.app:同req.app一样
2. res.append():追加指定HTTP头
3. res.set()在res.append()后将重置之前设置的头
4. res.cookie(name,value [,option]):设置Cookie
opition: domain / expires / httpOnly / maxAge / path / secure / signed
5. res.clearCookie():清除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);
}
});
6. res.download():传送指定路径的文件
7. res.get():返回指定的HTTP头
8. res.json():传送JSON响应
9. res.jsonp():传送JSONP响应
10. res.location():只设置响应的Location HTTP头,不设置状态码或者close response
11. res.redirect():设置响应的Location HTTP头,并且设置状态码302
12. res.send():传送HTTP响应
13. res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
14. res.set():设置HTTP头,传入object可以一次设置多个头
15. res.status():设置HTTP状态码
16. res.type():设置Content-Type的MIME类型
6. 请求对象(重点)
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静态文件
路由文件
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](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("我是首页homepage!!!
你的ip地址是:"+req.hostname+"_"+req.ip+"
");
});
6.5. 完整api
1. req.app:当callback为外部文件时,用req.app访问express的实例
2. req.baseUrl:获取路由当前安装的URL路径
3. req.body / req.cookies:获得「请求主体」/ Cookies
4. req.fresh / req.stale:判断请求是否还「新鲜」
5. req.hostname / req.ip:获取主机名和IP地址
6. req.originalUrl:获取原始请求URL
7. req.params:获取路由的parameters
8. req.path:获取请求路径
9. req.protocol:获取协议类型
10. req.query:获取URL的查询参数串
11. req.route:获取当前匹配的路由
12. req.subdomains:获取子域名
13. req.accpets():检查请求的Accept头的请求类型
14. req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages
15. req.get():获取指定的HTTP请求头
16. req.is():判断请求头Content-Type的MIME类型
7. 中间件(了解)
Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。
7.1. 中间件到底是什么
中间件(Middleware)本质就是一个函数,它可以访问请求对象(request object),响应对象(response object),和 web应用中处于请求-响应循环流程中的中间件,一般被命名为 next的变量。(next尾函数,执行下一个任务)
中间件的功能包括:
1.执行任何代码。
2.修改请求和响应对象。
3.终结请求-响应循环。
4.调用堆栈中的下一个中间件。
如果当前中间件没有终结请求-响应循环,则必须调用 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 静态页面
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("");
});
imgFileList.ejs 图片显示模板
图片上传展示