node.js—Express|node.js—Express 框架 day1(2019.6.4)
一、nrm
安装
参考地址:https://www.cnblogs.com/wangmeijian/p/7072053.html
二、express框架
安装
菜鸟教程参考网址:
https://www.runoob.com/nodejs/nodejs-express-framework.html
一、Express框架 Day05
1.课程介绍
- Express介绍(了解)
- Express安装及使用(掌握)
- Express路由(掌握)
- response响应对象(掌握)
- request请求对象(掌握)
- 中间件(了解)
Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。
Express 框架核心特性:
- 可以设置中间件来响应 HTTP 请求。
- 定义了路由表用于执行不同的 HTTP 请求动作。
(url = 资源) 映射 - 可以通过向模板传递参数来动态渲染 HTML 页面。 模板引擎
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、浏览器访问
文章图片
image.png 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项目)
文章图片
image.png
项目结构:
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
文章图片
image.png 5、启动express node app 需要设置监听端口
npm start
node ./bin/www
文章图片
image.png 6、浏览器访问
文章图片
image.png 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](http://localhost:3000/vip)///vip首页[http://localhost:3000/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 模板
- 锐客网
Welcome to
index.js 路由
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
//将视图和数据合并后发送给客户端});
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报错页面制作
文章图片
image.png
router.get('/err', function(req, res, next) {
//res.status(404).send("出错了:文件没有找到!");
res.status(404).render("error",{message:"很抱歉,您查看的宝贝不存在,可能已下架或者被转移。"});
});
error.ejs
文章图片
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);
}
});
文章图片
image.png
- 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.htmlpublic静态文件
路由文件
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;
【node.js—Express|node.js—Express 框架 day1(2019.6.4)】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("我是首页homepage!!!你的ip地址是:"+req.hostname+"_"+req.ip+"
");
});
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 应用就是在调用各种中间件。
文章图片
image.png
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();
…………………………. ………………………….
/*
- 中间件:
-
- 中间件是一个函数
-
- 中间件可以访问请求对象和响应对象
-
- 可以阻止请求继续执行,如果不阻止,可以调用尾函数 next()
- 尾函数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中只为我们提供了唯一一个中间件,其他的中间件需要安装。
属性 | 描述 | 类型 | 缺省值 |
---|---|---|---|
dotfiles | 是否对外输出文件名以点(.)开头的文件。可选值为 “allow”、“deny” 和 “ignore” | String | “ignore” |
etag | 是否启用 etag 生成 | Boolean | true |
extensions | 设置文件扩展名备份选项 | Array | [] |
index | 发送目录索引文件,设置为 false 禁用目录索引。 | Mixed | “index.html” |
lastModified | 设置 Last-Modified 头为文件在操作系统上的最后修改日期。可能值为 true 或 false。 | Boolean | true |
maxAge | 以毫秒或者其字符串格式设置 Cache-Control 头的 max-age 属性。 | Number | 0 |
redirect | 当路径为目录时,重定向至 “/”。 | Boolean | true |
setHeaders | 设置 HTTP 头以提供文件的函数。 | Function |
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("
文章图片