Nodejs的学习Ⅵ(express、ejs模板、关于get与post请求、中间件、nodemon与pm2、app.js文件的说明)

一、express的简单介绍与安装

ndoe.js,一个基于javsscript的服务器环境,它的出现使得javascript有能力去实现服务器操作。
而基于node.js的Express则把原先的许多操作变的简单灵活,一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。使用 Express 可以快速地搭建一个完整功能的网站。
express官网

Express的安装

其实express的安装可以省略,因为 可以用express的脚手架来生成这一切

cnpm install express --save			// 安装
express --version					// 查看express是否安装成功,如果显示版本号,则安装正确

Express脚手架的安装

方法1、使用express-generator安装
npm install express-generator -g	// 安装
express -h							// 查看命令行的指令含义

// 结果:
Options:
    --version        输出版本号
-e, --ejs            添加对 ejs 模板引擎的支持
    --pug            添加对 pug 模板引擎的支持
    --hbs            添加对 handlebars 模板引擎的支持
-H, --hogan          添加对 hogan.js 模板引擎的支持
-v, --view <engine>  添加对视图引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默认是 jade 模板引擎)
    --no-view        创建不带视图引擎的项目
-c, --css <engine>   添加样式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默认是普通的 css 文件)
    --git            添加 .gitignore
-f, --force          强制在非空目录下创建
-h, --help           输出使用方法
express --view=ejs app				// 创建了一个名为 app 的 Express 应用,并使用ejs模板引擎
cd myapp							// 进入app目录
npm install							// 安装依赖
set DEBUG=app:* & npm start			// 在Windows 下,使用该命令启Express应用
DEBUG=app:* npm start				// 在 MacOS 或 Linux 下,使用该命令启Express应用

最后输出结果:
在这里插入图片描述

// app文件内的目录:
bin: 启动目录 里面包含了一个启动文件 www 默认监听端口是 3000 (直接node www执行即可)
node_modules:依赖的模块包
public:存放静态资源
routes:路由操作
views:存放ejs模板引擎
app.js:主文件
package.json:项目描述文件
方法2:使用 express 命令 来快速从创建一个项目目录
express app -e						// express 项目文件夹的名字 -e 
cd app								// 使用命令行进入项目目录
cnpm install						// 安装依赖

二、Express路由简介与路由使用

路由简介

路由表示应用程序端点 (URI) 的定义以及响应客户端请求的方式。它包含一个请求方法(methods)路径(path)路由匹配时的函数(callback),如下

app.methods(path, callback);

app.get('/', (request, response) => {		// 举例
  response.send('<h1>hi,there</h1>')
})

路由方法

Express方法源于 HTTP 方法之一,附加到 express 类的实例。它可请求的方法包括:
get、post、put、head、delete、options、trace、copy、lock、mkcol、move、purge、propfind、proppatch、unlock、report、mkactivity、checkout、merge、m-search、notify、subscribe、unsubscribe、patch、search 和 connect。

Express路径与动态路由

Express路径包含三种表达形式,分别为字符串、字符串模式、正则表达式

1.字符串路径
app.get("/login",function(req,res){
	res.send("hi ,there!");
})

此路径地址将与/login匹配

2.字符串模式路径(类似于正则表达式模式)

此路由路径将与acdabcd相匹配。

app.get('/ab?cd', function (req, res) {
  res.send('ab?cd')
})

这条路线的路径将会匹配abcdabbcdabbbcd,这里只需要以ab开头,cd结尾即可。

app.get('/ab+cd', function (req, res) {
  res.send('ab+cd')
})

这条路线的路径将会匹配abcdabxcdabRANDOMcdab123cd,等。

app.get('/ab*cd', function (req, res) {
  res.send('ab*cd')
})

此路由路径将与/abe和相匹配/abcde

app.get('/ab(cd)?e', function (req, res) {
  res.send('ab(cd)?e')
})
3.正则表达式路径

此路由路径将匹配其中带有a的任何内容,因为路径 带有/ 所以需要使用转义

app.get(/\/a/, function (req, res) {
  res.send('home')
})

这条路线的路径将匹配butterflydragonfly

app.get(/.*fly$/, function (req, res) {
  res.send('/.*fly$/')
})

不过在使用正则表达式里面的特殊字符时需要使用转义

4.动态路由

路由参数被命名为URL段,用于捕获URL中在其位置处指定的值。捕获的值将填充到req.params对象中,并将路径中指定的route参数的名称作为其各自的键。

Request URL: http://localhost:3000/users/34/books/8989
Route path: /users/:userId/books/:bookId					// 匹配的URL段
req.params: { "userId": "34", "bookId": "8989" }			// 获得的对象

Request URL: http://localhost:3000/profile/userlihua
Route path: /profile/user:name
req.params: { "name": "lihua" }

使用路由参数定义路由,只需在路由路径中指定路由参数,如下所示。

app.get('/users/:userId/books/:bookId', function (req, res) {
  res.send(req.params)
})

路径参数的名称必须由“文字字符” ([A-Za-z0-9_]) 组成。

由于连字符(-)和点(.)是按字面解释的,因此可以将它们与路由参数一起使用

Request URL: http://localhost:3000/flights/LAX-SFO
Route path: /flights/:from-:to
req.params: { "from": "LAX", "to": "SFO" }

Request URL: http://localhost:3000/plantae/Prunus.persica
Route path: /plantae/:genus.:species
req.params: { "genus": "Prunus", "species": "persica" }

要更好地控制可以由route参数匹配的确切字符串,可以在括号()中附加一个正则表达式

Route path: /user/:userId(\d+)
Request URL: http://localhost:3000/user/42
req.params: {"userId": "42"}

由于正则表达式通常是文字字符串的一部分,因此请确保使用\对其他特殊字符进行转义
Express 4.x中,不以常规方式解释正则表达式中*字符。解决方法是使用{0,}代替*。这可能会在Express 5中修复。

路线处理程序

程序是在路由上施加先决条件,如果在没有使用next的情况下,则将不会路由的控制权传递给后续回调函数

路由处理程序可以采用函数函数数组二者组合的形式,如以下示例所示。

单个回调函数可以处理路由。例如:
app.get('/example/a', function (req, res) {
  res.send('Hello from A!')
})
多个回调函数可以处理一条路由(确保指定了next参数)。例如:
app.get('/example/b', function (req, res, next) {
  console.log('the response will be sent by the next function ...')
  next()
}, function (req, res) {
  res.send('Hello from B!')
})
回调函数数组可以处理路由。例如:
var cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

var cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

var cb2 = function (req, res) {
  res.send('Hello from C!')
}

app.get('/example/c', [cb0, cb1, cb2])
独立功能和功能数组的组合可以处理路由。例如:
var cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

var cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

app.get('/example/d', [cb0, cb1], function (req, res, next) {
  console.log('the response will be sent by the next function ...')
  next()
}, function (req, res) {
  res.send('Hello from D!')
})

response方法

这里的res就是response

方法描述
res.download()提示要下载的文件。
res.end()结束响应过程。
res.json()发送JSON响应数据给浏览器,是 JSON.stringify()与res.send()的结合。
res.jsonp()发送带有JSONP支持的JSON响应。
res.redirect()重定向请求。
res.render()渲染视图模板。
res.send()发送各种类型的响应。
res.sendFile()将文件作为八位字节流发送。
res.sendStatus()设置响应状态代码,并将其字符串表示形式发送为响应正文。

路由模块

以下示例将路由器创建为模块,在其中加载中间件功能定义一些路由,并 将路由器模块安装在主应用程序的路径上。

birds.js下:

var express = require('express')
var router = express.Router()

// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
  console.log('Time: ', Date.now())
  next()					// 必须调用next方法
})
// define the home page route
router.get('/', function (req, res) {
  res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
  res.send('About birds')
})

module.exports = router

然后,在应用程序(app.js)中加载路由器模块

var birds = require('./birds')
// ...
app.use('/birds', birds)

该应用程序现在将能够处理对/birds/birds/about的请求,以及调用timeLog特定于该路线的中间件功能。

app.set(name, value)

该方法的目的是给name赋值,也就是给变量赋值

app.set('title', 'My Site')						// 通过set方法赋值
app.get('title') // "My Site"					// 通过get方法取值

三、express的ejs模板

简介

相比于jade模板引擎,ejs对原HTML语言就未作出结构上的改变,只不过在其交互数据方面做出了些许修改,相比于jade更加简单易用。因此其学习成本是很低的。
您也可参考ejs官网

ejs基本使用

app.js文件:

const express=require("express");
const ejs=require("ejs");							// 引入ejs
const fs=require("fs");

var app=express();

app.set('views', path.join(__dirname, 'views'));	// 设置视图的对应目录,前一参数为变量名(一般取为视图的文件名),后一参数为视图的路径
app.set("view engine","ejs");						// 设置默认的模板引擎
app.engine('ejs', ejs.__express);					// 定义模板引擎

app.get("/",function(req,res){
	res.render("index.ejs",{title: "<h4>express</h4>"});	// 使用render来渲染模板,且要注意这里面的第二个参数必须为对象
});

ejs文件:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<% for(var i=0;i<10;i++){ %>				//  js的语法
			<%= i %>								// 输出为:0 1 2 3 4 5 6 7 8 9 
		<% } %>
		<% if(i == 10) { %>							// 为true
            <h1>i == 10</h1>						// 输出为:i == 10
            <h1>
                <%- i %>							//输出为:10 
            </h1>
        <% } %>
		<!-- 获取变量 -->
		<div class="datas">
			<p>获取变量:</p>
			<%- title %>							// 输出非转义的数据到模板,结果为:express的h4标签
			<%= title %>							// 输出数据到模板(数据是转义 HTML 标签),结果为:&lt;h4&gt;express&lt;/h4&gt;
		</div>
	</body>
</html>

这时我们会得到如下图的结果:
在这里插入图片描述
由此可以知道:

<% xxx %>:里面写入的是js语法,
<%= xxx %>:里面接受服务端发送给ejs模板的变量,不会解析变量里面的值(带<>符号),之所以输出类似与<h1>xxx</h1>,是因为对变量里的值(<>)进行了转义
<%- xxx %>:里面接受服务端发送给ejs模板的变量,会解析变量里面的值(会解析<>),输出XXX
<%# 注释标签,不执行、不输出内容

ejs标签各种含义

<% 		'脚本' 标签,用于流程控制,无输出。
<%_ 	删除其前面的空格符
<%= 	输出数据到模板(输出是转义 HTML 标签)
<%- 	输出非转义的数据到模板
<%# 	注释标签,不执行、不输出内容
<%% 	输出字符串 '<%'
%> 		一般结束标签
-%> 	删除紧随其后的换行符
_%> 	将结束标签后面的空格符删除

另外res.render()函数也是支持回调的,例如:

res.render('user', { name: 'Tobi' }, function(err, html) {
  console.log(html);
});

另外值得说明的是ejs模块也有ejs.render()和ejs.renderFile()方法,他在这里与res.render()作用类似,如下:

ejs.render(str, data, options);

ejs.renderFile(filename, data, options, function(err, str){
    // str => 输出绘制后的 HTML
});

四、express内的get请求

关于get一些说明

一般在网站开发中,get都用作数据获取和查询,且在发送请求后,可通过req.query对象可以获得用户发送的数据
实例

app.get("/login",function(req,res){
    console.log(req.query);
    res.send("登录路由,user为:"+req.query.username+"==>   password为:"+req.query.password);
});

五、express内的POST请求

关于post一些说明

相比于get请求,post所请求的数据会更加安全。
get请求会在地址栏显示输入的用户名和密码(有中文时会转化为BASE64加密),而post请求则会将数据放入http包的包体中,这使得别人无法直接看到用户名和密码!
我们的知道,首先我们得知道在form表单进行post请求enctype属性一般设置为 “application/x-www-form-urlencoded”,如果设置成multipart/form-data,则多用于文件上传

app.use(express.urlencoded({ extended: false }))// 设置解析中间件,用来解析post提交的数据

req.body.username 								// 获取post请求的数据

案例:

app.use(express.urlencoded({ extended: false }))//处理登陆请求
app.post('/login',async (req,res)=>{
	console.log(req.body);
    res.send("登录路由,user为:"+req.body.username+"==>   password为:"+body.query.password);
})

六、express内的中间件

从字面意思,我们可以了解到它大概就是做中间代理操作,事实也是如此;大多数情况下,中间件就是在浏览器发送请求服务器发送响应中间的一系列操作
事实上,express一个路由和中间件web框架

中间件函数 可以执行以下任务:执行任何代码;对请求和响应对象进行更改;结束请求/响应循环;调用堆栈中的下一个中间件函数。

中间件也分为应用层中间件、路由中间件、内置中间件、错误处理中间件和第三方中间件,且中间件自带两个参数(request、response)
下面分别对以下进行说明:

1.应用层中间件

应用级中间件绑定到app对象使用app.use和app.METHOD()
app.use([path,] callback [, callback…]) 是指定的一个或多个中间件函数安装在指定的路径上:当所请求路径的基数与path匹配时,将先执行中间件函数(截获),且当参数path省略时则默认为\(即访问任何页面,函数都会被调用)
app.METHOD(path, callback [, callback …])用于处理http请求,例如GET、PUT、POST,其实际的方法就是app.get()、app.post()、app.put()
例如下面实例:

app.use(function(req,res,next){
    console.log("访问任何页面,该函数都会被调用,且会在app.get()、app.post()等等之前被调用");
    next();
});

不过要注意的是如果不调用next方法那么地址会一直加载,因为我们在中间件里截取了函数,而如果要解决这个问题的话则需要调用next方法

2.路由中间件

路由级中间件和应用级中间件类似,只不过他需要绑定express.Router([options]),且他是为了配置复杂路由

var router = express.Router()

在匹配路由时,我们使用 router.use() 或 router.VERB() ,路由中间件若多次结合callback则可用于用户登录及用户状态检测。
例如:

// profile.js文件
var express = require('express');
var router=express.Router();
​
router.use("/user",function(req,res,next){
    console.log("分类:",req.originalUrl);		
    next();
},function(req,res){
    res.send("JavaScript");
});

module.exports = router;
// app.js文件
var app = express();            				// 创建app对象
var indexRouter = require('./routes/index');

app.use("/category",router);					// 配置路由界面

3.错误处理中间件

顾名思义,它是指当我们匹配不到路由时所执行的操作错误处理中间件和其他中间件基本一样,只不过其提供了4个自变量参数

var createError = require('http-errors');

// 处理404的中间件
app.use(function(req, res, next) {
  // 可以用该res.render('404.html');语句来生成好看的404页面,但是下面的next必须注释,
  // 且生成的404页面就会盖住错误信息
  next(createError(404));
});

// 处理错误的中间件
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');
});

一般情况下,我们把错误处理放在最下面,这样我们即可对错误进行集中处理。

4.内置中间件

从版本4.x开始,Express不再依赖Content,也就是说Express以前的内置中间件作为单独模块,express.static是Express的唯一内置中间件。

express.static(root, [options]);

通过express.static我们可以指定要加载的静态资源

5.第三方中间件

它采用引入 外部模块 的方式来获得更多的应用操作。如后期的cookie和session。

var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');

七、nodemon与pm2

nodemon

nodemon可在检测到目录中的文件更改时通过 自动重新启动节点应用程序来帮助开发基于node.js的 应用程序(热刷新) ,不过他是用于 开发阶段的工具

npm install -g nodemon				// 安装

// nodemon的使用
node main.js						// 启动文件,不能热刷新
nodemon main.js						// 启动文件,可以热刷新

pm2

PM2 是一个类似于Nodemon的工具,不同之处在于它用于生产环境,和Nodemon相似的地方在于他会监控你的app的任何修改或者重新部署,但是有更好的一面, PM2 在程序遭遇到崩溃的时候,他会正确重启你的app,并且pm2会在后台运行

npm install pm2 -g					// 安装

// pm2的使用
pm2 start main.js

八、app.js文件的说明

该网站目录访问顺序**:匹配/ => 匹配/users => 匹配/(默认)**
过程中只要一render则顺序链被打断 ,所以说app.js文件的执行是严格从上到下的

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');			// 导入首页路由
var usersRouter = require('./routes/users');			// 导入用户路由

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));		// 添加视图路径
app.set('view engine', 'ejs');							// 设置视图模板的引擎

app.use(logger('dev'));									// 开发时的日志
app.use(express.json());								// 服务器端的JSON解析
app.use(express.urlencoded({ extended: false }));		// 设置POST数据的解析
app.use(cookieParser());								// 设置cookie的解析
app.use(express.static(path.join(__dirname, 'public')));// 设置静态文件的解析

app.use('/', indexRouter);								// 首页路由
app.use('/users', usersRouter);							// 用户路由

// 处理404的中间件,且要注意这里的顺序是在其他的路由之后的
app.use(function(req, res, next) {
  // 可以用该res.render('404.html');语句来生成好看的404页面,但是下面的next必须注释,
  // 且生成的404页面就会盖住错误信息
  next(createError(404));
});

// 处理错误的中间件
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.ejs');
});

module.exports = app;

本文只用于个人学习与记录

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值