目录
express获取请求体数据
express可以使用body-parser包处理请求体
**应用场景:**试想,如果前端需要编写一个登录页面,在该页面可以填写登录账号与密码信息,点击提交之后,发送POST请求,并把数据以请求体的形式传递给服务器端,服务器端对POST请求体中的内容进行验证,以返回登录成功或者失败。
实现步骤:
构建前端页面:(前端页面放在服务器静态资源路径下,当访问/login路由时,返回该写好的页面即可)
a.html
html
<!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>
<div>
<form action="http://127.0.0.1:3002/login"
method="post">
username: <input type="text" name="username"><br/>
password: <input type="password" name="password"><br/>
<button>login</button>
</form>
</div>
</body>
</html>
构建服务器端响应:(并非完整代码,只是中间测试代码)
javascript
const express = require('express')
const app = express()
app.get('/login', (req, res) => {
console.log('1')
res.sendFile(__dirname + '/public/a.html')
})
app.post('/login', (req, res) => {
res.send('获取并处理用户信息')
})
app.listen(3002,()=>{
console.log('server start!')
})

提交表单时:(payload信息即为请求体)

在处理表单信息的步骤中,即需要使用body-parse来获取请求体信息:
安装:
javascript
npm i body-parser
导入:
javascript
const bodyParser = require('body-parser')
使用中间件:
(路由中间件,在需要处理请求体的路由中添加中间件)
body-parser提供的中间件:
javascript
//用于解析JSON格式请求体的中间件
const jsonParser = bodyParser.json()
//用于解析querystring格式请求体的中间件
const urlencodedParser = bodyParser.urlencoded({extended: false})
当中间件执行完毕时,会往req参数上添加一个body,body中包含了处理好的请求体数据。

本例中请求体是querystring形式的,因此使用下面的中间件,最终的完整代码:
javascript
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
//用于解析querystring格式请求体的中间件
const urlencodedParser = bodyParser.urlencoded({extended: false})
app.get('/login', (req, res) => {
res.sendFile(__dirname + '/public/a.html')
})
app.post('/login',urlencodedParser, (req, res) => {
if(req.body.username==='admin' && req.body.password==='123456'){
res.send('login success')
}else{
res.send('login fail')
}
})
app.listen(3002,()=>{
console.log('server start!')
})
防盗链
思考这样一种情形,我们想把一个网络上的图片放到自己的项目里,如果直接在img标签的src属性中粘贴图片地址,有时候图片可以显示,有时候却是空白的。如果图片显示空白,说明该图片的网站使用了防盗链技术,也就是说,该网站阻止了其他网站对其资源的访问。
**原理:**在实现上,防盗链通过禁止该域名之外的其他域名访问本域名的资源来实现。
防盗链的访问不是只限制图片,通常包括域名下的所有资源。
使用express实现防盗链:
在前端和服务端发送HTTP请求时,HTTP请求的请求头部分,referer请求头中包含了发送当前请求URL的协议、域名、端口。
根据防盗链的原理,可以在服务器端对referer进行判断:如果是本域名,则返回请求的资源,如果不是,则返回404。
具体代码:
目录结构:

在index.js中,访问根目录返回public下的a.html,在a.html中,访问静态资源11.png。
a.html:
html
<!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>
<div>
<h2>静态资源</h2>
<img src="/11.png">
</div>
</body>
<script>
</script>
</html>
index.js:
javascript
const express = require('express')
const app = express()
app.use((req, res, next)=>{
console.log('----')
//获取referer
let referer = req.get('referer')
if(referer){
let url = new URL(referer)
let hostname = url.hostname
console.log(hostname)
if(hostname !== '127.0.0.1'){
console.log('1')
res.status(404).send(`<h1>404 not found</h1>`)
return
}
}
next()
})
app.use(express.static(__dirname + '/public'))
app.get('/', (req, res) => {
console.log("2")
res.sendFile(__dirname + '/public/a.html')
})
app.listen(3002,()=>{
console.log('server start!')
})

访问127.0.0.1:


访问localhost:


路由模块化
在之前的笔记介绍的方法中,所有的路由都是放在index.js下的,但是,随着项目功能的增多,路由逻辑可能变得非常多,如果都写在index.js下,代码量会非常大,不便于阅读和维护。
可以采用模块化的思想来解决这个问题。
把路由进行拆分,放在不同的模块(js)文件中。
步骤:
在服务器项目下创建routes文件(也可以不是这个名字,但常规是这样)。
在routes下创建多个js文件,每个js文件对应一部分路由。
在每个js内部,创建router实例,router的用法和app是一样的,只是把语法中的app替换成router,最后暴露router:
(homePageRouter.js)
javascript
const express = require('express')
const router = express.Router()
router.get('/home', (req, res)=>{
res.send('home page')
})
router.get('/search',(req, res)=>{
res.send('search page')
})
module.exports = router
在index.js中引入这个模块,然后使用app.use让其生效,在该模块中配置的路由即可生效:
(index.js)
javascript
const express = require('express')
const app = express()
const homeRouter = require('./routers/homePageRouter')
app.use(homeRouter)
app.use(express.static(__dirname + '/public'))
app.listen(3002,()=>{
console.log('server start!')
})
目录结构:


在对路由进行模块化之后,主模块的体积会变小,也便于维护和阅读。在多人开发时,也会降低冲突。
router可以看成是小型app对象。
模板引擎
模板引擎是分离用户界面和业务数据的一种技术。通俗来说,是分离HTML和JS的技术。
为什么需要分割HTML和JS?对于Node.js来说,JS指的是服务器端的JS,而不是浏览器端的JS,对于前端来说,HTML和JS当然可以是混合的,但是对于服务器端来说,有时候,服务器需要响应一个HTML数据,而HTML数据中可能包含一些JS语句。如果把该HTML和其中的JS单独写在一个静态资源里,一般是不能够正确获取JS数据的:
比如,当访问/home时,返回一个HTML,HTML有一个h2标签,标签内容是一个指定的字符串:

(index.js)
javascript
const express = require('express')
const app = express()
let homestring = 'hello home :)'
app.use(express.static(__dirname + '/public'))
app.get('/home', (req, res) => {
res.send(`<!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>
<div>
<h2>${homestring}</h2>
</div>
</body>
<script>
let homestring = 'hello world :)'
</script>
</html>`)
})
app.get('/test',(req, res)=>{
res.sendFile(__dirname + '/public/a.html')
})
app.listen(3002, () => {
console.log('server start!')
})
(a.html)
html
<!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>
<div>
<h2>{{homestring}}</h2>
<h2>${homestring}</h2>
</div>
</body>
<script>
let homestring = 'hello world :)'
</script>
</html>
访问/home:

访问/test:

模板引擎在很多语言中都具有,并不是js独有的。随着前后端分离,该技术使用较少,但仍然需要了解。
EJS
EJS是一个高效的js模板引擎。
使用EJS实现上述例子的步骤如下:
1.安装
javascript
npm i ejs
2.引入
javascript
const ejs = require('ejs')
3.使用ejs渲染
javascript
ejs.render('xxxx <%= params %>',{params: params})
,其中,render方法会对内部的字符串参数(第一个参数)进行解析,遇到<%= 变量名 %>的标识时,会把内部的变量名替换成第二个对象参数中变量名key对应的value。
使用ejs,可以完成如下效果:

index.js
javascript
const ejs = require('ejs')
const fs = require('fs')
let username = 'mashiro'
const renderHtml = fs.readFileSync('./public/a.html').toString()
console.log(
ejs.render(renderHtml, {username: username})
)
a.html
html
<!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>
<h2>hello, <%= username %></h2>
</body>
</html>
使用这种方式,可以实现html和js的分离:html在本例中是a.html文件,而js在index.js中,在渲染时,把需要渲染的js数据传入ejs.render即可,可以根据不同的情况渲染不同的数据。
ejs列表渲染
列表渲染:批量输出列表内容。
**需求:**在html中渲染ul标签,ul内部的li对应一个数组,数组中每个值对应一个li。
不使用ejs时,普通的实现方法:
javascript
const color = ['orange', 'blue', 'green', 'white']
let str = '<ul>'
color.forEach((item)=>{
str += `<li>${item}</li>`
})
str += '</ul>'
但是此时html代码和js代码是耦合在一起的。
使用ejs实现:

index.js
javascript
const ejs = require('ejs')
const fs = require('fs')
const color = ['orange', 'blue', 'green', 'white']
const html = fs.readFileSync('./public/a.html').toString()
let resule = ejs.render(
html,
{ color }
)
console.log(resule)
a.html
html
<!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>
<ul>
<% color.forEach(item => { %>
<li><%= item %></li>
<% }) %>
</ul>
</body>
</html>
在本例中,使用<% JS语法 %>,可以在<%与%>之间的部分编写JS语法。
也就是说,对于ejs来说,碰到<% %>格式,会把其中的内容作为JS语句解析。碰到<%= %>部分,会把其中的内容作为变量解析。
ejs条件渲染
**需求:**通过isLogin决定前端页面输出的内容,如果isLogin为true,则显示 欢迎!,如果为false,显示登录注册页面。
使用原生JS实现:
javascript
let isLogin = false
if(isLogin){
console.log(`<span>欢迎!</span>`)
}else{
console.log(`<button>登录</button>
<button>注册</button>`)
}
使用ejs实现:

index.js
javascript
const ejs = require('ejs')
const fs = require('fs')
const html = fs.readFileSync('./public/a.html').toString()
let isLogin = false
let result = ejs.render(
html,
{isLogin}
)
console.log(result)
a.html
html
<!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>
<ul>
<% if(isLogin){ %>
<span>欢迎!</span>
<% }else{ %>
<button>登录</button>
<button>注册</button>
<% } %>
</ul>
</body>
</html>
在express中使用ejs

index.js
javascript
const express = require('express')
const path = require('path')
const app = express()
app.set('view engine', 'ejs')
app.set('views', path.resolve(__dirname,'./views'))
app.get('/home', (req, res)=>{
res.render('a', {title:':)'})
})
app.listen(3002,()=>{
console.log('server start!')
})
a.ejs
html
<!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>
<h2>hello, <%= title %></h2>
</body>
</html>