当我们初学前端时,常常只关注页面效果和交互,但随着项目复杂度提升,我们迟早会遇到"服务端"的问题:如何让一个页面的数据是从数据库来的?怎么让不同的用户看到不同的内容?这时候,我们就需要一个后端框架来帮我们处理这些需求。而对于 JavaScript 开发者来说,Express 是入门服务端开发最友好的一把钥匙。
本文不会长篇大论地讲解底层原理,而是通过最直观、最简单的方式,带你快速理解:什么是服务器、路由、中间件,以及 Express 的核心用法。如果你刚刚接触 Node.js,希望用它写点后端的东西,这篇文章就是为你准备的。
1.Express的简单使用
express 是node中的服务器软件(封装的http模块),通过express可以快速的在node中搭建一个web服务器。
使用步骤
1.创建初始化项目
创建文件夹然后终端输入 npm init -y
2.安装express
npm install express
3.创建index.js 编写代码
javascript
//引入express
const express = require('express')
//一切皆对象服务器在程序里面也是对象
//获取服务器的实例对象
const app = express()
/*
如果希望服务器可以正常访问 则需要为服务器设置路由
路由可以根据不同的请求方式和请求地址来处理用户请求
app.METHOD(...)
METHOD可以是get post
中间件
-在express中我们使用app.use定义一个中间件
中间件和路由很像 用法很像
通常情况下 我们访问的直接是路由 但是有时候想要加一个中间件
但是路由不区分请求的方式 只看路径
只要访问的路径包含它就可以访问到
和路由的区别
1.会匹配所有的请求
2.路径设置父目录
*/
//中间件
//next是回调函数的第三个参数 调用函数后可以触发后续的中间件
app.use('/',(req,res,next)=>{
console.log('收到请求')
// res.send('中间件给你的响应')
next()//next不能在响应处理完毕之后调用
})
app.use('/',(req,res)=>{
console.log('收到请求')
res.send('中间件给你的响应2222')
})
//中间件用来干嘛 可以用来设置访问路由之前的权限 相当于访问路由之前设置一些(公关)处理
//http://localhost:3000
//现在创建了一个路由 / (路由是接口)
//路由的回调函数执行的时候 会接受三个参数
//第一个 request 第二个response
app.get('/hello',(req,res)=>{
console.log('有人访问我了')
//在路由中 应该做两件事
//读取用户的请求(request)
//req表示用户的请求信息 通过req可以获取用户的传递数据
console.log(req.url)//用户请求的路由
//根据用户的请求返回响应(response)
//res表示服务器发送给客户端的响应信息
//sendStatus()像客户端发送响应状态码
// res.sendStatus(9999999)
//status只是设置了状态码没有发送
res.status(200)
//send设置发送响应体
res.send('这是我给你的东西 但其实没东西')
})
//启动服务器
//app.listen(端口号)用来启动服务器
//服务器就像一个房子就我们的计算机有非常多的软件
//怎么识别我们的服务器软件
//端口楼里面的门牌号 3000端口号房间号 就是express服务你
//后面可以加一个回调函数 服务器启动后执行函数 现在可以通过3000端口访问服务器
//协议名://ip地址:端口号/路径
//http://localhost:3000/index.js localhost === 127.0.0.1都是指本计算机
app.listen(3000,()=>{
console.log('服务器已经启动')
})
中间件就是当我们访问路由的时候,如果设置了中间件,就会被中间件拦截,这里就是可以给路由设置一些权限要求等。
2.nodemon工具以及中间件的作用
目前服务器代码修改后必须重启,希望有一种方式可以监视代码的修改。代码修改以后可以自动重启服务器 需要安装一个模块 nodemon(监视器)
使用方式
1.全局安装 npm install nodemon -g
终端输入nodemon 就可以了 修改代码可以自动重启
默认启动当前目录的index.js 如果不是index.js 加上名字 nodemon ./01_helloworld.js
2.在项目中安装 npm install nodemon -D 开发依赖
启动 npx nodemon npx执行node模块
当我们创建express实例之后,实际上express有非常多的功能的。但是我们需要在中间件之中进行配置。比如我们希望当我们get访问http://localhost:3000/index.html。
也就是服务器的代码希望可以被外部直接访问,我们就需要在中间件中配置静态资源目录。可以将页面html以及图片放进去这样可以从服务器获取到这些代码。
javascript
const express = require('express')
const path = require('node:path')
//创建服务器实例
const app = express()
//use()中间件
//配置路由
//设置这个中间件之后 浏览器访问时会自动去public目录下寻找是否有静态资源
app.use(express.static(path.resolve(__dirname,'./public')))
app.get('/',(req,res)=>{
/*
希望用户访问我的根目录 我可以返回一个网页
*/
res.send('')
})
app.get('/login',(req,res)=>{
//获取到用户名和密码
//req.query表示查询字符串中的请求参数
console.log(req.query)
console.log(req.query.username)
if(req.query.username==='奥巴马'&&req.query.password==='123123'){
console.log('请求收到')
res.send('登录成功')}else{
res.send('登录失败')
}
})
//启动服务器
app.listen(3000,()=>{
console.log('服务器启动')
})
这样我们就可以直接从浏览器获取到服务器中的页面了。用express.static设置静态文件目录,然后把希望外部可以直接访问的资源放进去就可以了。就可以通过文件名直接访问了。
这里req和res就是请求和响应信息。
3.get请求的两种参数传递以及post请求
1.get请求
xml
<form action="/login" method="get">
<div>
用户名 <input type="text" name="username">
</div>
<div>
密码 <input type="text" name="password">
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
javascript
const express = require('express')
const path = require('node:path')
const app = express()
//配置一个静态资源的路径
//express很多功能都是中间件引入的
app.use(express.static(path.resolve(__dirname,'./public')))
//引入解析请求体的中间件
app.use(express.urlencoded())
///开头的路径 叫做绝对路径 /login实际上是 http://localhost/login
app.get('/login',(req,res)=>{
if(req.query.username==='admin'&&req.query.password === '123123'){
res.send('<h1>登录成功</h1>')
}else{
console.log('<h1>登录失败</h1>')
}
})
当我们直接用get方法发送请求的时候,我们在输入框输入的数据会在req.quert中以对象的形式传递过来,而我们直接在路径上设置参数的话。
javascript
//get请求发送参数第二种方式
///hello/:id 表示访问/hello/xxx时就会触发
//在路径中以冒号命名的部分我们称为param 在get请求它会被解析为请求参数
//params传递参数一般不会特别复杂 一般就是一个
app.get('/hello/:id',(req,res)=>{
//约定由于配置
//可以通过req.params获取参数
console.log(req.params)
//{ id: '123', age: '12', gender: '男' }
res.send('<h1>这是hello路由</h1>')
})
就会存储到params中,而且这个参数是在地址栏里面填写的。两种方式本质是相同的,params按照顺序传递。
2.post请求
post请求需要请求体,也就是body。但是我们express默认是没有给我们添加这个功能的,我们可以用中间件添加这个功能。
javascript
//引入解析请求体的中间件
app.use(express.urlencoded())
app.post('/login',(req,res)=>{
console.log(req.query) //{}
//默认情况下express不会自动解析请求体 需要中间件添加功能
console.log(req.body)
const username = req.body.username
const password = req.body.password
if(username==='admin'&&password==='123123'){
res.send('<h1>登录成功</h1>')}
else{
res.send('登录失败')
}
})
然后就可以接收post请求了。参数通过body拿取。
4.简单的登录案例
我们现在会写get和post路由了,那么我们就可以写简单的登录案例,比如当我们登录的时候,发送请求到这个路由,然后携带参数过来。我们提前写死一些账户然后进行对比,有的话就登录没有的话就返回登录失败。还有注册功能,当我们访问的注册路由的时候,携带参数过来,如果写死的账户里面没有,那么就用数组的方法把注册的参数数据推进去形成新用户。
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>我是一个静态网页</h1>
<hr>
<h2>登录</h2>
<form action="/register" method="post">
<div>
用户名 <input type="text" name="username">
</div>
<div>
密码 <input type="password" name="password">
</div>
<div>
确认密码 <input type="password" name="repwd" placeholder="确认密码">
</div>
<div>
<input type="texx" name="nickname" placeholder="昵称">
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
</body>
</html>
javascript
const express = require('express')
const path = require('node:path')
const app = express()
//创建一个数组存储用户信息
const USERS =[
{
username:'admin',
password:'123123',
nickname:'超级管理员'
},
{
username:'孙悟空',
password:'123123',
nickname:'用户'
}
]
app.use(express.static(path.resolve(__dirname,'./public')))
app.use(express.urlencoded())
app.get('/login',(req,res)=>{
if(req.query.username==='admin'&&req.query.password === '123123'){
res.send('<h1>登录成功</h1>')
}else{
res.send('登录失败')
console.log('<h1>登录失败</h1>')
}
})
app.get('/hello/:id',(req,res)=>{
//约定由于配置
//可以通过req.params获取参数
console.log(req.params)
//{ id: '123', age: '12', gender: '男' }
res.send('<h1>这是hello路由</h1>')
})
app.post('/login',(req,res)=>{
const username = req.body.username
const password = req.body.password
// USERS.map(user=>{
// if(user.username === username){
// if(user.password===password){
// res.send(登录成功 ${user.nickname})
// return
// }
// }
// })
// res.send('登录失败')
const loginUser = USERS.find(item=>{
return item.username === username && item.password===password
})
if(loginUser){
res.send(登录成功 ${loginUser.nickname})
}else{
res.send('登录失败')
}
// if(username==='admin'&&password==='123123'){
// res.send('<h1>登录成功</h1>')}
// else{
// res.send('登录失败')
// }
})
app.post('/register',(req,res)=>{
//获取用户登录的数据
console.log(req.body)
const {username,password,repwd,nickname} = req.body
//只验证用户名是否存在
const user = USERS.find(item=>{
return item.username === username || item.nickname === nickname
})
if(!user){
//进入判断用户不存在
USERS.push({
username,
password,
nickname
})
res.send('恭喜你注册成功')
}else{
res.send('用户名存在')
}
})
//params以及查询字符串本质上没有区别 查询字符串对象形式传递参数 params按照顺序传
app.listen(3000,()=>{
console.log('服务器启动了')
})
这些代码就实现了登录注册的基本功能。
5.模板引擎
当然学后端node.js只是了解基本使用,比较现在还是主打前端开发。这里我们默认没有前端动态展示数据库数据,我们现在服务器写死一些数据希望可以去动态的展示,我们希望有一个东西,可以嵌套变量,在node里面叫做模板。
html是静态页面 不会跟随服务器数据变化而变化。希望有一个东西 长的像网页 但是可以嵌套变量 这个东西node里面叫做模版。node存在很多个模版引擎 template engines 比如ejs。
ejs是node中的一款模版引擎 使用步骤
1.安装ejs
2.配置express模版引擎为ejs
app.set('view engine','ejs')
3.配置模版路径
app.set('views',path.resolve(__dirname,'views'))
注意 模版引擎需要被express渲染后用户才能使用
res.render()用来渲染一个模版引擎并将其返回给浏览器 render就是把ejs渲染并且返回给用户跟react 一样的 只不过react在前端这里是后台 后端环境。
编辑
这是模板的目录需要放到views文件夹中。
javascript
const express = require('express')
const app = express()
const path = require('node:path')
const STUDENT = [
{
name:'sun',
age:123,
gender:'男',
address:'花果山'
},
{
name:'zhu',
age:231,
gender:'女',
address:'高老庄'
}
]
//将ejs配置为默认的模版引擎
app.set('view engine','ejs')
//配置模版路径
app.set('views',path.resolve(__dirname,'views'))
//配置静态资源路径
app.use(express.static(path.resolve(__dirname,'public')))
//配置请求体解析 body
app.use(express.urlencoded())
//解析json请求体
//app.use(express.json())
/*
可以写路由了
*/
app.get('/hello',(req,res)=>{
res.send('hello')
})
//我们希望用户访问student路由的时候 可以返回一个页面里面有表格 存放的student数据
app.get('/students',(req,res)=>{
//render可以将一个对象作为render的第二个参数传递 这样在模版中可以访问到对象中的数据
//res.render('students',{name:'sun',age:'18'})//名字和ejs名一致
//<%=name %>在ejs输出内容时 自动对字符串中的特殊符号进行转义 < 不会识别为标签
//这个设计主要是为了避免xss 攻击
//<%- %>会直接运行h1 以及js脚本等等
res.render('students',{STUDENT})
})
//在所有路由的后面配置错误路由
//不写路径会匹配所以路径 上面路由都没有匹配到
app.use((req,res)=>{
//这个执行 上面的路由都没有匹配
res.status(404)
res.send('你访问的地址被外星人劫持')
})
app.listen(3000,()=>{
console.log('服务器已经启动')
})
这里我们用render去渲染我们的模块,这样访问这个路由就可以返回一个页面给浏览器。然后第二个参数是对象,可以将动态展示的数据传递到模板,模板进行展示。
编辑
这里是模板的写法,仍然是html写法只不过变量需要用<%= %>获取js代码需要<%%>包裹。
说到底,Express 并不是一个神秘的东西,它只是对原生 Node HTTP 模块的一层"封装和简化"。我们只要记住三件事:
它帮我们创建服务器(app.listen())
它让我们能轻松写路由处理请求(app.get()、app.post())
它通过中间件机制帮我们定制各种服务逻辑
加上它对静态资源、模板引擎的良好支持,我们就能快速搭建出一个真正能跑的 Web 项目。