這篇文章為大家帶來了關於express的相關知識,Express 是基於 Node.js 平台,快速、開放、極簡的 Web 開發框架,希望對大家有幫助。
Express 是基於Node.js 平台,快速、開放、極簡
的Web 開發框架。 建立web伺服器
Express 的本質:就是一個 npm 上的第三方套件,提供了快速建立 Web 伺服器的便利方法。
使用Express開發框架可以非常方便、快速的創建Web網站的伺服器或API介面的伺服器
#官方網址:https://www.expressjs.com.cn/
下載安裝:
npm init -ynpm i express -S
使用步驟:
const express = require('express')const app = express()app.get(路由,回调) // get是请求方法app.listen(端口号)
#請求方法也支援:
get - 查詢請求- 條件在位址列
post - 新增請求- 資料在請求主體
put - 修改請求- 條件在網址列- 資料在請求主體
delete - 刪除請求- 條件在網址列
各個動詞方法用來處理對應的請求。不過有一個方法除外:
app.all() // 可以用来处理任意请求方式
雖然all方法可以處理任意請求,但是盡量少用,甚至盡量不要使用。
使用postman進行調試
完全匹配
// 匹配根路径的请求app.get('/', function (req, res) { res.send('root');});// 匹配 /about 路径的请求app.get('/about', function (req, res) { res.send('about');});// 匹配 /random.text 路径的请求app.get('/random.text', function (req, res) { res.send('random.text');});
不完全匹配
// 匹配 acd 和 abcdapp.get('/ab?cd', function(req, res) { res.send('ab?cd');});// 匹配 abcd、abbcd、abbbcd等app.get('/ab+cd', function(req, res) { res.send('ab+cd');});// 匹配 abcd、abxcd、abRABDOMcd、ab123cd等app.get('/ab*cd', function(req, res) { res.send('ab*cd');});// 匹配 /abe 和 /abcdeapp.get('/ab(cd)?e', function(req, res) { res.send('ab(cd)?e');});
字元?、 、 * 和() 是正規表示式的子集,- 和. 在基於字串的路徑中按照字面值解釋。
正規比對:
// 匹配任何路径中含有 a 的路径:app.get(/a/, function(req, res) { res.send('/a/');});// 匹配 butterfly、dragonfly,不匹配 butterflyman、dragonfly man等app.get(/.*fly$/, function(req, res) { res.send('/.*fly$/');});
#使用一個回呼函數處理路由:
app.get('/example/a', function (req, res) { res.send('Hello from A!');});
多次處理:
app.get('/example/b', function (req, res, next) { console.log('这处理完之后会交给下一个函数处理'); 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('response will be sent by the next function ...') next()}, function (req, res) { res.send('Hello from D!')})
res.download() // 提示下载文件。 res.end() // 终结响应处理流程。 res.json() // 发送一个 JSON 格式的响应。 res.jsonp() // 发送一个支持 JSONP 的 JSON 格式的响应。 res.redirect() // 重定向请求。 res.render() // 渲染视图模板。 res.send() // 发送各种类型的响应。 res.sendFile() // 以八位字节流的形式发送文件。 res.sendStatus() // 设置响应状态代码,并将其以字符串形式作为响应体的一部分发送。
download範例:
// 响应下载 - res.download(被下载的源文件,下载后的文件名称,回调函数)res.download("./test.html",'b.html',err=>{ if(err){ console.log("下载失败"); }else{ console.log("下载成功"); }})
json範例:
// 给客户端响应json数据// res.json(json格式的数据)let obj = { name:"张三", age:12, wife:"翠花", children:['阿大','阿二','小明']}res.json(obj)
jsonp範例:
// 给客户端发起的jsonp请求做响应,响应的是json数据// res.jsonp(json格式的数据)let obj = { name:"张三", age:12, wife:"翠花", children:['阿大','阿二','小明']}res.jsonp(obj)
redirect範例:
// res.redirect() 用来跳转路由的 - /a这个路由,其实/b这个路由就正好可以处理他,就可以在/a这个路由处理中,将这次请求交给/b这个路由去处理res.redirect('/index')app.get('/index',(req,res)=>{ let data = fs.readFileSync('./test.html') res.end(data)})
send範例:
// res.send() - 用于给客户端响应字符串的 - 字符串中如果是标签,可解析成html - 自动设置数据类型和编码let html = ` <h2>这是一个h2标签</h2> `// res.end 不会自动设置数据类型,也不会设置编码// res.end(html)res.send(html)
sendFile範例:
// res.sendFile() 用于给客户端响应一个文件res.sendFile(__dirname + '/test.html')
sendStatus範例:
// sendStatus是自动设置响应状态码,并将对应的响应状态描述响应给客户端 res.sendStatus(404) // 响应 not found res.sendStatus(200) // 响应 ok
req.url // 请求的路径 - 如果有?传参,这个路径中也会带有参数 req.method // 请求方法 req.path // 请求路径 - 如果有?传参,这个路径中不包含参数 req.protocol // 协议 req.params // 获取get请求的参数 - 针对动态路由传参 - restful风格的参数 - 最终获取到的是对象,对象的键,就是路径指定的名称 req.query // 获取get请求的参数 - 针对传统形式传参 - 使用?参数 - 最终获取到的是对象
express提供了一個非常好用的方法,叫做express.static ()
,透過此方法,可以非常方便地建立一個靜態web資源伺服器:
app.use(express.static('public')) // app.use()表示使用(中间件) // 现在可以访问public目录下所有的文件 // 如public/aa.jpg文件,则可以通过 : http://xxxx/images/aa.jpg
express也支援為靜態資源檔案建立一個虛擬的檔案前綴(實際上檔案系統中並不存在),可以使用express.static
函數指定一個虛擬的靜態目錄,就像下面一樣:
前綴的使用意義:
- 可以迷惑別人,某種程度上阻止別人猜測我們伺服器的目錄結構
- 可以幫助我們更好的組織和管理靜態資源
app.use('/static', express.static('public'))
前綴前面的「/」必須要加,否則就錯。 【404】
現在你可以使用/static
作為前綴來載入public
資料夾下的檔案:
http://localhost:3000/static/images/kitten.jpg http://localhost:3000/static/css/style.css http://localhost:3000/static/js/app.js http://localhost:3000/static/images/bg.png http://localhost:3000/static/hello.html
#使用app.use()方法一般寫在具體的路由監聽之前。
每個應用程式可有多個靜態目錄。
app.use(express.static('public'))app.use(express.static('uploads'))app.use(express.static('files'))
路由在生活中如撥打服務電話時,按數字幾能處理什麼樣的處理,它就是類似於按鍵與服務之間的映射關係。在Express中,路由指的就是客戶端發起的請求(位址)與伺服器端處理方法(函數)之間的對應關係。
express中的路由分3部分組成,分別是請求類型(方法)、請求uri(位址)和對應的處理函數。
當一個客戶端請求到達服務端之後,先經過路由規則匹配,只有匹配成功之後,才會呼叫對應的處理函數。在匹配時,會按照路由的順序進行匹配,如果請求類型和請求的URL 同時匹配成功,則Express 會將這次請求,轉交給對應的函數進行處理。
app.<get>(uri,(req,res)=>{})// use方法并不是请求类型方法,但是它放的位置与请求方法一致</get>
意義:將原本可能寫在一個文件中的路由規則,分割成若干個路由文件(js文件,一個js文件就是一個模組)。
顧名思義,將路由進行模組化,以模組(js檔案)為單位進行管理,物以類聚。
核心思想:能拆就拆(拆到不能拆為止,解耦,高內聚,低耦合)。
在開發專案時,如果將所有的路由規則都掛載到入口檔案中,程式編寫和維護都變得更加困難。所以express為了路由的模組化管理功能,透過express.Router()方法創建路由模組化處理程序,可以將不同業務需求分開到不同的模組中,從而便於程式碼的維護和專案擴展。
步驟:
指定那個路徑開頭的請求,用app.use(路徑開頭,處理模組)
app.use('/admin',adminRouter) // /admin开头的请求路径,交给adminRouter模块处理app.use('/front',frontRouter) // /front开头的请求路径,交给frontRouter模块处理
這個模組未定義,定義這個模組
let {adminRouter} = require('./admin/admin')let {frontRouter} = require('./front/front')
导入的文件还未定义,创建文件
const express = require('express')const adminRouter = express.Router() // 创建路由对象// 通过路由对象处理剩余的请求adminRouter.get('/goods',(req,res)=>{ res.send('这是admin模块的goods页面')})// 导出模块module.exports = {adminRouter}
此时,我们又两种方案去处理请求:
同一个请求路径使用不同的请求方法多次请求的简写:
app.route('/book') .get(function(req, res) { res.send('Get a random book'); }) .post(function(req, res) { res.send('Add a book'); }) .put(function(req, res) { res.send('Update the book'); });
中间件(middleware)可以理解为业务流程的中间处理环节,可以理解成中间过滤器。
中间件可以分类可分如下几类:
内置中间件,也就是express本身自带无需npm安装
第三方中间件
非 Express 官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中可以通过npm进行安装第三方中间件并配置,从而提高项目的开发效率。例如body-parser (解析post数据的)此中间件可以很方便帮助我们获取到post提交过来的数据。
自定义中间件,开发者自己编写的(中间件的本质其实就是一个function)
如果从使用层面去考虑,中间件可以划分为:
express提供了好用的内置中间件,如提供一个静态资源管理的中间件,通过此中间件就可以帮助为我们快速搭建一个静态资源服务器:
app.use('前缀',express.static('托管目录地址'))
在express中,除了内置的express.static()
中间件,还内置了另外2个常用的中间件:
express.json()
app.use(express.json())
req
请求对象的body
属性上使用示例:
// 有了这个中间件以后,我们可以从客户端给服务器端发送json数据,这个json数据会放到请求对象req的body属性上app.use(express.json())app.post('/p1',(req,res)=>{ // express.json中间件可以让数据挂在req的body属性上 console.log(req.body); res.send('this p1 request is ended')})
首先必须是post请求,然后必须有数据,但是数据不能是以前的 x-www-form-urlencoded这样的数据,必须是raw的数据
然后请求头的content-type 必须是 application/json
express.urlencoded()
app.use(express.urlencoded({extended: false}))
req
请求对象的body
属性上注意,
- 后面提及的这2个常用内置中间件存在兼容性问题。
- 上述2个中间件都说把数据处理之后挂到req.body上,但是实际上并不会出现我们想的覆盖的问题。
案例:使用json、urlencoded中间件来接收json数据与表单post数据,发送可以通过postman来进行
自定义中间件,其本质就是定义一个处理请求的函数,只是此函数中除了有request和response参数外还必须包含一个next参数,此参数作用让中间件能够让流程向下执行下去直到匹配到的路由中发送响应给客户端。也可以通过给request对象添加属性来进行中间件数据的向下传递
function mfn(req,res,next){ //. 自己需要定义的逻辑流程 // 中间件最后一定要执行此函数,否则程序无法向下执行下去 next()}
注意:在整个请求链路中,所有中间件与最终路由共用一份req
和res
案例:依据上述的共用特性,自定义一个中间件来接收post提交的表单数据(意义:内置那中间件是不是存在兼容性问题)
在express中,其允许我们使用第三方的中间件来进行对数据进行处理。比较典型的例如:可以使用第三方中间件来接收post数据。
以使用body-parser
中间件来接收post数据为例,步骤如下:
body-parser
npm i -S body-parser
body-parser
app.use(body.urlencoded({extended: false}))
req.body
获数post中数据在使用的时候,
body-parser
库的语法与前面看的express内置的express.urlencoded
中间件的语法非常相似,原因是内置中间件是基于body-parser
来实现的。
其他第三方中间件:http-proxy-middleware/cors/cookie-session …
**作用:**专门用来捕获整个项目发生的异常错误,从而防止项目异常崩溃的问题产生(友好显示异常)。
**格式:**错误级别中间件的函数参数中,必须有四个形参,分别是(err,req,res,next)
问:多出来的err参数有什么作用呢?
答:里面包含了错误的信息,err.message属性中就包含了错误的文本信息,这个信息可以在中间件中输出给用户看。
app.get('/',(req,res) => { throw new Error('服务器内部发生了致命的错误!') res.send('Welcome to my homepage')})app.use((err,req,res,next) => { console.log('发生了错误:' + err.message) res.send('Error!' + err.message)})
**案例:**要求指定一个路径(可能路由对应的文件不存在),读取文件内容,输出给用户
注意事项:错误级别中间件要想发挥其作用,必须写在所有的路由的后面,是否是app.listen
之前无所谓。
**作用:**用于处理404的请求响应
// 假设定义这个路由,但是实际请求的时候请求了/12345,这个时候就会404app.post("/1234", (req, res, next) => { res.send('你请求成功了')});// 404的输出// 该中间件也需要写在最后(与异常中间件的顺序无所谓,只要确保其在所有的路由方法之后就可)app.use((req,res,next) => { // 输出404错误 res.status(404).send('<h1>404</h1>') // 先指定404状态码,然后再输出错误信息})
404错误中间件也要求在所有的正常请求路由的后面去声明使用,不要放在路由的前面,否则会导致后面的路由都是404错误。
**注意点:**错误级别的中间件,必须在所有路由之后注册,至于404中间件与异常中间件,谁先谁后无所谓。
模板页面:页面:https://404.life/
cookie的原理是在浏览器中开辟了一个用来存储http请求中的数据,第一次保存之后,下次请求只要还是使用的当前浏览器,就能访问到浏览器这个空间中的数据。
cookie会作为键值对,在响应头和请求头之间携带。
cookie的特点:
npm i cookie-parser -S
使用:
// 导入 const cookieParser = require('cookie-parser') // 中间件 app.use(cookieParser()); // 请求头获取 req.headers.cookie // 获取所有cookie // 响应头设置 res.cookie(键,值,{maxAge: 有效期-毫秒}) // 设置cookie
cookie是存储在浏览器的,所以安全性不高,所以一些重要数据就不能存储在cookie中,且cookie的存储空间有限制,所以就有了session。
session是存储服务器端的,session需要依赖cookie,session数据存储会在cookie中存放一个sessionid,这个sessionid会跟服务器端之间产生映射关系,如果sessionid被篡改,他将不会跟服务器端进行隐射,因此安全系数更高。且session的有效期比较短。通常是20分钟左右,如果浏览器在20分钟内没有跟服务器进行交互,服务器就会删除session数据。
npm i cookie-session -S
使用:
// 导入:const session = require('cookie-session')// session配置session({ name:"sessionId", secret:"asdfasdfqwer", // 给sessioinId加密使用的秘钥,随便填写 maxAge:20*60*1000 // 20分钟})// 设置sessionreq.session[键] = 值// 获取sessionreq.session[键]
npm i bcryptjs -S
使用:
var bcrypt = require('bcryptjs'); // 加密 密文 = bcryptjs.hashSync(明文[,数字]); // 数字,将使用指定的轮数生成盐并将其使用。推荐 10 // 验证 bcryptjs.compareSync(明文,密文); // 通过返回true,失败返回false
npm install jsonwebtoken
使用:
// 加密生成tokenvar jwt = require('jsonwebtoken');var token = jwt.sign(被加密的对象, 盐);// 验证jwt.verify(token, 盐, function(err, decoded) { // decoded是解密后的对象});
npm i multer -S
使用:
var multer = require('multer')var upload = multer({ dest: path.join(__dirname,'public','image') }) // 指定上传的文件路径app.post('/profile', upload.single('上传表单name值'), function (req, res, next) { // req.file 是上传的文件信息 - 可以从中获取到文件名称、路径、后缀 - 拼接路径存入mongodb})
npm i mysql -S
使用:
// 导入const mysql = require("mysql");// 创建连接对象const db = mysql.createConnection({ host:"localhost", user:"root", password:"root", database:"test"});// 连接db.connect(err=>{ if(err){ console.log("连接失败,错误:"+err); return; } console.log("连接成功");});// 执行语句db.query("",(err,result)=>{ if(err){ console.log("失败,错误:"+err); return; } console.log("成功"); console.log(result);});
npm i svg-captcha -S
使用:
const svgCaptcha = require('svg-captcha') // 创建验证码 let captcha = svgCaptcha.create(); // captcha是是一个对象,其中包含data键和text键,text是验证码上的字符,data是一个svg标签直接可以显示为一张图片
npm install nodemailer --save
使用:
const nodemailer = require('nodemailer')// 1. 创建发送器const transport = nodemailer.createTransport({ // 需要你发送放邮箱的 stmp 域名和密码和一些其他信息 // 需要你去复制一下, 找到下载的 nodemailer 第三方包 // nodemailer -> lib -> well-known -> services.json "host": "smtp.qq.com", "port": 465, "secure": true, // 证明你的身份 auth: { // 发送方邮箱的用户名 user: '邮箱号', // stmp 允许密码 pass: '授权码' }})// 2. 发送邮件transport.sendMail({ // 从那个邮箱发送 from: '发送方邮箱', // 发送到哪里, 可以写一个字符串, 书写邮箱, 也可以写一个数组, 写好多邮箱 to: ['接收方邮箱', '接收方邮箱'], // 邮件标题 subject: '标题', // 本次邮件的 超文本 内容 html: ` 您好: 本次的验证码是 <h1> 2345 </h1> 请在 3 分钟内使用 <br> ------------------------<br> 前途无限股份有限公司 `, // 本次邮件的 文本 内容 // text: ''}, function (err, data) { if (err) return console.log(err) console.log('邮件发送成功') console.log(data)})
在一个web应用程序中,如果只是使用服务器端代码来编写客户端html代码,前后端不分离,那么会造成很大的工作量,而且写出来的代码会比较难以阅读和维护。如果只是使用客户端的静态的HTML文件,那么后端的逻辑也会比较难以融入到客户端的HTML代码中。为了便于维护,且使后端逻辑能够比较好的融入前端的HTML代码中,同时便于维护,很多第三方开发者就开发出了各种Nodejs模板引擎,其中比较常用的就是Jade/Pug、Ejs和art-template 等模板引擎。
目的:使后端逻辑能够比较好的融入前端的HTML代码中,同时便于维护
网址:
art-template 是一个简约、超快的模板引擎。
开发模式:
传统开发模式:
前端代码和后端代码写在了一起
混合在了一起,但是这种文件有要求,文件通常都是后端语言的文件中才能写后端的逻辑 - 这样的话,对于我们前端攻城狮特别不友好,因为我们前端攻城狮负责html页面,但是在html页面中不能写后端的逻辑,如果将html页面放在后端的文件中,我们又需要学习后端语言
此时,模板引擎出现了 - 模板引擎其实就是让我们可以在html页面中书写后端的逻辑 - 循环/判断 …
模板引擎有很多种:jade/ejs/art-tamplate …
模板引擎最终能在html中写逻辑,相当于我们代码前后端混合在一起的一种语法,最终为什么能被浏览器所识别?因为浏览器在识别之前,我们的模板引擎需要进行编译 - html代码
前后端分离开发模式:
html一个人去写;
后端接口另一个人去写;
双方之间对接,使用接口文档
html上所有的数据,都是通过ajax请求回来,并通过dom操作显示在页面中的
模板引擎渲染速度测试:
特性
下载安装:
# 安装 npm i -S art-template express-art-template
配置:
// 模板引擎配置 // 指定art-template模板,并指定模块后缀为.html app.engine('html', require('express-art-template')); // 指定模板视图路径 app.set('views', path.join(__dirname, 'views')); // 省略指定模块文件后缀后名称(可选,在渲染时可以省略的后缀) app.set('view engine', 'html')
art-template 支持**标准语法与原始语法**。标准语法可以让模板易读写,而原始语法拥有强大的逻辑表达能力。标准语法支持基本模板语法以及基本 JavaScript 表达式;原始语法支持任意 JavaScript 语句,这和 Ejs一样。
使用art-template展示一个视图(html文件)
将视图放入views目录下(允许分目录)
编写代码,展示视图的方式是`res.redner(文件的路径)
app.get('/', (req, res) => { // 输出视图 res.render('404.html')})
控制层返回数据(在js控制层中赋值变量到视图中)
app.get(uri,(req,res)=>{ res.render(模板,{ username: '张三', age: 25, gender: '女', hobby: ['篮球','乒乓球','羽毛球'] })})
变量输出:
<!-- 标准语法 -->{{ username }}<!-- 或者 --><!-- 原始语法 -->
在默认情况下,上述输出方式不能将带有HTML标记的内容让浏览器解析,只会原样输出。如果需要将HTML标记让浏览器,则请使用下述方式输出数据:
<!-- 标准语法 -->{{@ username}}<!-- 原始语法 -->
条件判断:
{{if 条件}} … {{else if 条件}} … {{/if}} … …
循环:
<!-- 支持 数组和对象的迭代 默认元素变量为$value 下标为$index 可以自定义 {{each target val key}}-->{{each 循环的数据}} {{$index}} {{$value}} {{/each}} {{each 循环的数据 val key}} {{key}} {{val}} {{/each}}
如果使用默认的键、值的名字(index,value)则其前面的
$
一定要写!一定要写!!!如果使用的自定义的键、值的名字,则前面的
$
一定不能写!!不能写!!
模板导入:
{{include '被引入文件路径'}}
- 如果是当前路径下的一定要写
./
,不写则从磁盘根下开始寻找- 被include的文件后缀名默认为
.art
,如果不是请勿省略- 在子模板中最好不要有html、head和body标签(否则容易出现样式错误的问题)
模板继承:
被继承的模板:
<meta> <!-- 类似于vue的插槽 --> <title>{{block 'title'}}My Site{{/block}}</title> <!-- block占位符 content此占位的名称 --> {{block 'content'}}{{/block}}
需要继承的子模板:
<!--extend 继承 -->{{extend './layout.html'}} {{block 'title'}}首页{{/block}} {{block 'content'}} <p>This is just an awesome page.</p>{{/block}}
bootcss在线构建器:https://www.bootcss.com/p/layoutit/
更多编程相关知识,请访问:编程入门!!
以上是建議收藏!帶你手把手教你入門express的詳細內容。更多資訊請關注PHP中文網其他相關文章!