Nodejs之express框架学习

  • Post author:
  • Post category:其他




Express框架学习笔记


MDN永远的神

参考资料


安装 Express – Express 中文文档 | Express 中文网 (expressjs.com.cn)

[express框架 – 小火柴的蓝色理想 – 博客园 (cnblogs.com)](https://www.cnblogs.com/xiaohuochai/p/7189074.html#:~:text=Express是一个简洁、灵活的 node.js Web 应用开发框架%2C 它提供一系列强大的特性,帮助开发者创建各种 Web 和移动设备应用。 本文将详细介绍express框架,对Express的描述,它是一个基于 Node.js 平台,快速、开放、极简的 web 开发框架。 优点是易上手、高性能、扩展性强 1、易上手:nodejs最初就是为了开发高性能web服务器而被设计出来的,然而相对底层的API会让不少新手望而却步。 express对web开发相关的模块进行了适度的封装,屏蔽了大量复杂繁琐的技术细节,让开发者只需要专注于业务逻辑的开发,极大的降低了入门和学习的成本)


Express Web Framework (Node.js/JavaScript) – 学习 Web 开发 | MDN (mozilla.org)

尚硅谷视频

官方文档


Express 4.x – API Reference – Express 中文文档 | Express 中文网 (expressjs.com.cn)

Express是一个简洁、灵活的 ,基于node.js 平台的Web 应用开发框架, 它提供一系列强大的特性,帮助开发者创建各种 Web 和移动设备应用。

Express框架建立在node.js内置的http模块上。



安装

  1. 初始化npm包环境

    npm init
  2. 下载express包

    npm i express -S

    ,现在的版本会自动保存在运行环境的,

    npm i express --no-save
  3. 当然也可以使用yarn安装

    yarn add express

image-20211108193337783



Hello Express

// 引入express包
const express = require('express');

// 创建应用对象
const app = express();

// 路由的配置
app.get('/',(request,response)=>{
    // send是exprss封装的,它会自动设置utf-8字符集
    // 不用再设置reponse.setHeaders("content-Type",'text/html;charset=utf-8');
    response.send("Hello Express");
});

// 启动服务,监听端口
app.listen(80, ()=>{
    console.log('端口80监听中');
})



路由



什么是路由

路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。

之前其实就已经接触过了,http请求,我们根据路径调用指定的回调函数。所以这里是由路由来分配,交给指定的回调函数。

路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成的。

访问的路径‘/’即为router的路径。



路由的组成

第一部分:HTTP请求的方法(get或post,或者是其他的请求方法)

第二部分:URL路径

第三部分: 回调函数



代码实现

const express = require('express');
const fs = require('fs');
const app = express();

// 创建路由规则
// 如果request的请求时get类型,并且url路径是'/',那么就交个这个路由来处理
// 这样就不用写太多的if else 了
app.get('/',(request,response)=>{
    response.send('路由页面')
});
app.get('/admin',(request, reponse) =>{
    reponse.send('后台页面');
})
app.get('/login',(request, reponse) =>{
    let body = fs.readFileSync('./2-login.html');
    reponse.end(body);// 这里必须使用end
})
app.get('/register',(request, reponse) =>{
    reponse.send('注册界面页面');
})
app.post('/login',(request, reponse) =>{
    reponse.send('登录成功');
})
// 可以响应任意的请求
app.all('test',(request,response)=>{
    response.send('任意类型');
})
app.listen('80');

登录界面html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 这里的action建议写出这样,要不然域名一换,就不能骑做了,写出这样自动与url相拼接 -->
    <form action="/login" method='post'>
        <input type="text" name="uername">
        <input type="password" name="pwd">
        <input type="submit">
    </form>
</body>
</html>

当Express服务器接收到一个HTTP请求时,它会查找已经为适当的HTTP方法和路径定义的路由

如果找到一个,Request和Response对象会被创建,并被传递给路由的回调函数

我们便可以通过Request对象读取请求,通过Response对象返回响应



内网穿透可以让别人访问自己内网



修改hosts文件的作用

路径:

C:\Windows\System32\drivers\etc\hosts

修改这个文件可以本地解析域名,具有较高的优先级。

比如这样设置

127.0.0.1	qq.com

这样设置的话,其实访问qq.com 其实就是访问的我的主机。



request对象

官方api:

Express 4.x – API Reference – Express 中文文档 | Express 中文网 (expressjs.com.cn)

Request对象是路由回调函数中的第一个参数,代表了用户发送给服务器的请求信息。

通过Request对象可以读取用户发送的请求包括URL地址中的查询字符串中的参数,和post请求的请求体中的参数。



获取请求方法

request.method



获取请求HTTP协议版本

request.httpVersion



获取请求的URL

request.url



获取请求头信息

request.headers

给headers后面加属性名,还可以获得它的属性,比如

request.headers.host

这个可以获取主机名。



获取get请求查询字符串

**属性/**

方法

描述
request.query 获取get请求查询字符串的参数,拿到的是

一个对象
request.query

返回的结果

{ vip: 'true', hh: '1' } //http://localhost/req?vip=true&hh=1



获取get请求参数路由的参数

文档原文:This property is an object containing properties mapped to the

named route “parameters”

. For example, if you have the route , then the “name” property is available as . This object defaults to .

/user/:name``req.params.name``{}

在url中使用

/:xxx

可以给那个对象添加属性。

**属性/**

方法

描述
request.params 获取get请求参数路由的参数,拿到的是一个对象
app.get('/req/:id',(request,response)=>{
    // 这里给那么空对象添加id属性
    console.log(request.params.id);
    response.end('hhh');
});



获取post请求体

**属性/**

方法

描述
request.body 获取post请求体,拿到的是一个对象(要借助一个中间件)

获取请求头中指定key对应的value

**属性/**

方法

描述
request.get(xxxx) 获取请求头中指定key对应的value

除了

request.headers.xxx

来获取请求头里面的属性,还可以使用

request.get(xxx)

来获取请求头里面的属性,比如

request.get(host)

来获取请求头里面的主机名。



response对象

这个基本和nodejs元素的属性和方法相同。

Response对象是路由回调函数中的第二个参数,代表了服务器发送给用户的响应信息。

通过Response对象可以设置响应报文中的各个内容,包括响应头和响应体。

基本除了响应体,其他的都别写中文。

**属性/**

方法

描述
response.send() 给浏览器做出一个响应
response.end() 给浏览器做出一个响应(不会自动追加响应头)
response.download() 告诉浏览器下载一个文件

response.sendFile()
给浏览器发送一个文件里面内容(就不用手动fs了) ,地址必须是绝对路径(__dirname)
response.redirect() 重定向到一个新的地址(url)比如说

https://www.baidu.com

,它的响应状态码是302就是跳转的意思,响应头里面有个

Location

,它的值就是浏览器跳转的地址,浏览器看到过后会自动跳转过去。

有一个实际的应用就是,登录跳转,若发现用户没有登录,则转到登录界面。
response.set(header,value)/setHeaders() 自定义响应头内容
res.status(code)/res. setStatus 设置响应状态码
res.statusMessage 设置响应字符串(一般成功就是OK)


有一个地方需要注意(千万要注意)


response.send()

会自动设置响应头的字符集,所以下述代码会报错

response.write('1234');
response.send('hhh');// 在write也就是发完内容给客户端之后,不能在设置响应头了,所以这里会报错。
// 所以这里只能用response.end('hhh'); 而且还要设置响应头
// response.setHeaders('Content-type','text/css;charset=utf-8');



静态资源设置


利用 Express 托管静态文件 – Express 中文文档 | Express 中文网 (expressjs.com.cn)

一定要看看上面的链接

image-20211111181250686

可以用来

设置网站的根目录(经过实验看来只能放一层目录?也就是代码和public同一层级目录下)

。不用再像原生的一样,每次都需要自己拼接了,而不再需要自己设置报错了。

const express = require('express');
const app = express();
// 配置网站根目录
app.use(express.static(__dirname + '/public'));
app.get.......
// 它会先去根目录里面找有没有相关的资源,如果没有,那么就看看有没有相关的响应路由。根目录的优先级最大,若路由和根目录同名里面的文件同名,那么使用根目录里面的文件。

注意:所有文件的路径都是相对于存放目录的,因此,存放静态文件的目录名不会出现在 url 中。

网站的根目录一般放html、css、JavaScript、img、audio、音频、字体文件。这些资元一般不太变化。

对于频繁变化的规则则需要设置路由规则来响应请求。

image-20211111180901360



中间件

官网文档

Writing middleware for use in Express apps – Express 中文文档 | Express 中文网 (expressjs.com.cn)


Express 中间件_w3cschool

(不错)

中间件(Middleware) 是一个函数,它可以访问请求对象(request), 响应对象(response) 和

web 应用中处于请求-响应循环流程中的中间件

,一般被命名为 next 的变量。

Middleware functions can perform the following tasks:

  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next middleware in the stack.

If the current middleware function does not end the request-response cycle, it must call to pass control to the next middleware function. Otherwise, the request will be left hanging.

next()

(否则,请求将会被挂起)。如果没有next,那么在这个中间件就必要完成响应。

另外,你还可以同时装在一系列中间件函数,从而在一个挂载点上创建一个子中间件栈。(先挂载,先执行)

image-20211111145843475


其实感觉就是抽离了公共部分的代码,将其分装成一个函数,更加的方便多个调用,避免大量重复。比如对查询字符串的某些判断,一些每个路由都会用到的处理

一个例子(个人理解)

// 中间件就是函数
const express = require('express');

const app = express();
const f1 = function (request,reponse,next) {
    console.log(1);
    next();
}
const f2 = function (request,reponse,next) {
    console.log(2);
    next();
}
app.use(f1);
app.use(f2);

app.get('/',(request,response)=>{
    response.send('中间件');
})
app.listen(80);

上述代码执行时请求一次输出

1 2

。分析一下代码,我们定义了两个函数f1 和 f2, 然后将其挂载在app上,那么当前执行的实现,先执行f1函数,调用next,执行f2函数,调用next发现没有中间件了,那么返回app.get,继续执行当前的内容。



中间件的分类

直接看

Express 中间件_w3cschool

给特定的某个路由设置中间件还可以这样做:

image-20211111164435095

现在只有静态资源的中间件被express内置。

image-20211111165238207

比如说轮播图这些就是动态资源。



请求体参数中间件

需要使用请求体中间件来获取请求体的参数。

之前是怎么做的呢?

requset.on('data',chunk=>{
    body += chunk;
});
requset.on('end',()=>{
    body = querystring.parse(post);
})

现在我们可以引入一个第三方的中间件

body-parser


body-parser – npm (npmjs.com)

下载

yarn add body-parser

var express = require('express')
var bodyParser = require('body-parser')
 
var app = express()
 
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
app.use(function (req, res) {
  res.end(req.body)// 直接可以获取请求体对象
})



路由中间件

把所有路由都写在一个页面不方便维护和管理。

路由.js

// 安装 express
// 引入 express 包
const express = require('express');
// 创建应用对象
const app = express();
// 
const router = require('./routes/router');
const adminRouter = require('./routes/admin');
// 挂载
app.use(router);
app.use(adminRouter);

//1. 创建一个 routes 文件夹
//2. 创建单独的文件 router.js
//3. 修改 router.js 中代码(四步)
//4. 主文件中引入 router.js
//5. app.use 设置中间件

// 监听端口 启动服务
app.listen(80, () => {
    console.log('服务已经启动.. 端口 80 监听中....');
});

router.js

//1. 引入 express 包
const express = require('express');
//2. 创建路由器对象  router 是一个微型的 app 对象
const router = express.Router()

//3. 修改路由
router.get('/home', (request, response) => {
    response.send('home 页面');
});

router.get('/home.html', (request, response) => {
    response.send('<h1>home.html</h1>')
})

router.get('/videos', (request, response) => {
    //数据处理  读取数据库  读取文件
    response.send('电影列表页');
});

router.get('/x/cover/:id.html', (request, response) => {
    //获取id
    let id = request.params.id;
    //获取 电影的信息 JSON 
    // 与 HTML 结构拼接 形成最终的 HTML (响应体)
});
//4. 暴露router对象
module.exports = router;



模板引擎

模板引擎就是为了使用用户界面与业务数据(内容)分离而产生的。简单来说,

使用模板引擎来动态渲染数据

。下面学习ESJ模板引擎。

在没有模板引擎之前,服务端的htm文件是和JavaScript一起书写的,很难做到分离。

image-20211111194930706

因为来引入数据,那么就是有在js里面写html,如果不这样,那么将意味着你读取html文件后讲不知道数据需要插入的位置在哪里。

其实使用模板引擎就相当于使用一个特殊的占位符,js解析的时候可以知道需要渲染的数据在哪里就可以了。

所以需要做代码分离。

模板引擎有哪些:[推荐13款javascript模板引擎-阿里云开发者社区 (aliyun.com)](https://developer.aliyun.com/article/293805#:~:text= ICanHaz.js 是一个简单而且功能强大的客户端的 JavaScript 模板引擎。 Dotpl-JS 是一个纯javascript模板引擎%2C支持IF和FOR关键字,多循环衔套及字段渲染,跨浏览器支持。,是一个实用的javascipt工具%2C页面静态化利器! 13. EJS EJS 可以将数据和模板合并然后生成 HTML 文本。)

这里主要学习的是EJS:

EJS – 嵌入式 JavaScript 模板引擎 | EJS 中文文档 (bootcss.com)

安装

yarn add ejs

引入ejs

const ejs = require('ejs');



一、变量的拼接

语法是

<%= %>

// 调用方法,render两个参数 
// str 要编译的字符串
// data  数据对象
let str = '<h1><%=msg%><h1>'
let data = {msg:'需要渲染的信息'};
const res = ejs.render(str,data);
console.log(res);

这样我们就可以吧html和js分开了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1><%=msg%></h1>
</body>
</html>
// 引入ejs
const ejs = require('ejs');
const fs = require('fs');
// 调用方法,render两个参数 
// str 要编译的字符串
// data  数据对象
let str = fs.readFileSync('./1.html').toString();
let data = {msg:'需要渲染的信息'};
const res = ejs.render(str,data);
console.log(res);



二、数据的遍历

可以使用for循环,但是在html中怎么使用呢?使用<%for {%> xxx <%}%>

这样基本上就在html使用JavaScript的语法了,比如forEach,if这些什么的。

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul>
        <%for(let i=0;i<msg.length;i++){ %>
            <li><%= msg[i] %></li> <!-- 这里子自动添加到ul中>
        <%}%>
    </ul>
</body>
</html>

js

// 引入ejs
const ejs = require('ejs');
const fs = require('fs');
// 调用方法,render两个参数 
// str 要编译的字符串
// data  数据对象
let str = fs.readFileSync('./1.html').toString();
let data = {msg:[
    "1",
    "2",
    "3",
    "4",
    "5"
]};
const res = ejs.render(str,data);
console.log(res);

做一个小案例:小说列表

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul>
        <%for(let i=0;i<msg.length;i++){ %>
            <li><%= msg[i] %></li>
        <%}%>
    </ul>
</body>
</html>

js

const express = require('express');
// 引入ejs
const ejs = require('ejs');
const fs = require('fs');
const app = express();
// 调用方法,render两个参数 
// str 要编译的字符串
// data  数据对象
let data = {msg:[
    "黎明之剑",
    "我的治愈系游戏",
    "炼狱艺术家",
    "诸界末日在线"
]};
app.get('/novels',(request,response)=>{
    let content = fs.readFileSync('./1.html').toString();
    content = ejs.render(content,data);
   response.end(content);
});
app.listen(80,()=>{
    console.log("starting");
});



三、判断

<% if(xx) {%>
<%}%>



四、ejs在express中应用

设置express的模板引擎

// 设置使用的模板引擎
app.set('view engine', 'ejs');// view engine 必须写这个
// 设置模板存放的位置(html代码)
app.set('views','./views') // views 也必须这样写

使用响应

// 这是去./view 下面的寻找 play.ejs  注意后缀。 data还是数据对象
response.render('player',data);



版权声明:本文为fujiaxu666原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。