Express framework from entry to soil

foreword

The Express framework is a minimalist and flexible web development framework based on the Node.js platform. Encapsulates the http module of Nodejs. We can achieve many functions through the Express framework.

To study this article, you need to have the front-end three-piece set and the foundation related to sending requests, as well as the related foundation of Nodejs (http module). These are all involved in the author's column, you can view:

Front-end and back-end interaction knowledge reserve
Nodejs

Without further ado, let's start learning.

1. First experience

First, package management initialization is required:

npm i init -y

Then you need to download the express package:

npm i express

Next, let's write the following code:

//导入express
const express = require('express')
//创建实例对象
const app = express()

//创建路由
app.get('/home', (req, res) => {
    
    
    res.end('hello express')
})

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

After writing the following code, the terminal runs:

insert image description here
Open 127.0.0.1:3000/home:
insert image description here

Second, routing

2.1 What is routing

Official definition: Routing determines how an application responds to a client's request for a specific endpoint.

2.2. Use of routing

Routing consists of:Request method, path, callback function.

Express provides a series of methods that make it easy to use routing:

app.<method>(path.callback)

Among them, the method can be get or post, which is very similar to the http module.

Here is a special case:

app.get('/', (req, res) => {
    
    
    res.end('home')
})

When sending a request, it is empty on the surface, but in fact there is a / in the message.

When accessing the home page, the path is generally not set actively, and the routing rule above responds.

insert image description here
There is also a special route:

app.get('*', (req, res) => {
    
    
    res.end('404 not found')
})

In this routing rule, * means that requests other than the other routing rules written above will return 404.

In addition, let me talk about a special one, but it is a special method:

app.all('/text', (req, res) => {
    
    
    res.end(test)
})

The above string of code, whether it is get or post, will return test.

2.3 Get request message parameters

The framework encapsulates some APIs to facilitate the acquisition of data in the request message, and is compatible with the acquisition method of the native HTTP module.

Let's take a look at the native operations first:

const express = require('express')

const app = express()

app.get('/request', (req, res) => {
    
    
    // 原生操作
    console.log(req.method)//获取请求方法
    console.log(req.url)//获取请求url
    console.log(req.httpVersion)//获取http版本
    console.log(req.header)//获取请求头部
    res.end('hello express')
})

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

The above methods can still be used in the express framework. It is because express is compatible with the http module.

Let's take a look at the running results:
insert image description here
Then let's take a look at how to get the request message parameters under the express framework:

    console.log(req.path)//获取路径
    console.log(req.query)//获取查询字符串
    console.log(req.ip)//获取ip
    console.log(req.get('host'))//获取某个请求头

Send a request with parameters this time:
insert image description here
the result displayed on the console is:
insert image description here

2.4 Wildcarding of ids

Here from the front-end point of view. For example, I want to make a product page.

There will be many products on the product page, and the display format of each product after clicking is the same, but the content is different. Each product has an id in the database.

Then when we send a request to apply for a product, should we write the route corresponding to the id of each product? No.

We can write a wild card of id, so that each id send request can respond to the corresponding data:

app.get('/:id.html', (req, res) => {
    
    
    //获取路由参数
    console.log(req.params.id)//获取id
    res.send('产品')
})

No matter which parameter follows the request, the corresponding page can be obtained:
insert image description here

2.5 Response settings

The native http response is still applicable in the express framework.

Let's take a look at the native response-related settings:

app.get('/response', (req, res) => {
    
    
    // 原生响应
    res.statusCode = 400;//状态码
    res.statusMessage = 'love'//响应信息
    res.setHeader('xxx', 'yyy')//响应头
    res.write('hello express')//设置响应体1
    res.end('response')//设置响应体2
    res.end('response')
})

Then look at the configuration related to the response in express:

    //express响应
    res.status(500);//状态码
    res.set('aaa', 'bbb')//响应头
    ResizeObserver.send('你好')//响应体
    // 其他响应
    res.redirect('http://baidu.com')//路由重定向

Three, middleware

3.1 Middleware overview

The essence of middleware is a callback function. The function is to encapsulate some public operations and simplify the code.

Middleware functions can access the request object request and the response object response just like routing.

The role of middleware: use functions to encapsulate public operations and simplify code.

There are two types of middleware: global middleware and routing middleware.

3.2 Comparison between global middleware and routing middleware

Here is an example. We go to the train station to take the bus, there will probably be two ticket checks. The first time is when we enter the waiting hall, we need to scan the ID card to check the ticket. During this process, people of different trains can enter the waiting hall through the ticket gate as long as there is a train to do on this day.

When we entered the waiting hall, the time was up, and we checked in again. This time the ticket is checked at the ticket gate, and after the ticket is passed, you can go to the respective trains. When checking tickets, people on the same train will check tickets together. Instead of everyone swarming up.

We can think of the first ticket as global middleware; the second ticket as routing middleware.

Once the global middleware is enabled, it will be used when each request is initiated; and once the routing middleware is enabled, the corresponding route will be used when the request is initiated.

The above is the difference between global middleware and routing middleware.

3.3 Use of global middleware

Say a requirement, and we will implement it. First look at the following routing rules:

app.get('/home', (req, res) => {
    
    
    res.send('前台首页')
})

app.get('/admin', (req, res) => {
    
    
    res.send('后台首页')
})

app.all('*', (req, res) => {
    
    
    res.send('<h1>404 Not Found</h1>')
})

Now let's talk about the requirements: when each request is initiated, record the requested url and ip in a file.

The following is the analysis:
Since every request initiation must be recorded, each route requested needs to be processed with a response. So is a global middleware. It was also said before that global middleware is a function. So we can define this function outside:

//声明中间件函数
function recordMiddleware(req, res, next) {
    
    

}
app.use(recordMiddleware)

app.get('/home', (req, res) => {
    
    
    res.send('前台首页')
})

app.get('/admin', (req, res) => {
    
    
    res.send('后台首页')
})

app.all('*', (req, res) => {
    
    
    res.send('<h1>404 Not Found</h1>')
})

== This function has three parameters: req, res, next. ==As mentioned earlier, the middleware function can get the req and res of the route. In addition, there is one more parameter: ==next. == This next parameter is a function type.

The next parameter, we can understand it this way: when the middleware function is called, next will be called. After calling next, it will continue to call the route or the next middleware.

Next, let's take a look at the complete code for the above requirement:

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

//声明中间件函数
function recordMiddleware(req, res, next) {
    
    
    let {
    
    url, ip} = req;
    fs.appendFileSync(path.resolve(__dirname, './assess.log'), `${
      
      url} ${
      
      ip}\r\n`)
    next()
}
app.use(recordMiddleware)

app.get('/home', (req, res) => {
    
    
    res.send('前台首页')
})

app.get('/admin', (req, res) => {
    
    
    res.send('后台首页')
})

app.all('*', (req, res) => {
    
    
    res.send('<h1>404 Not Found</h1>')
})
app.listen(3000, () => {
    
    
    console.log('服务器已经启动,端口3000正在监听...')
})

For the above code, let me talk about the inside of the middleware function, which is mainly related to nodejs. If you want to simply understand middleware, you can also skip it.

In this code, we import the fs and path modules. First, the url and ip in the req (request message) are obtained by destructuring assignment. Secondly, we use appendFileSync in the fs module. The function of this api is to use the fs module to write things in the file. Because the suffix Sync is added at the end, it is synchronous. No). Let's talk about the inside of the function that writes something in the file. The path module is used internally. The resolve function is a spliced ​​string. The first parameter is the address of the file (writing something), and the second parameter is the content to be written. The content uses the operation of the string variable. Write in the url and ip obtained before.

at lastCall next to prove that the above has been executed, and you can continue to execute middleware or routing.

== It should be noted that the global middleware needs app.use, which is equivalent to registering the global middleware. After registration, it can be used normally. ==The complete code is above, if you are interested, you can copy and paste it to play.

The last thing to say is that global middleware can call multiple.

The above is the relevant explanation of global middleware.

3.4 Use of partial middleware

Let me talk about the requirements first: For the requests of /admin and /setting, the URL is required to carry the code=521 parameter, and the shortlist carries the prompt [wrong password].

Look at the basic code first:

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

app.get('/admin', (req, res) => {
    
    
    res.end('12321')
})

app.get('/setting', (req, res) => {
    
    
    res.end('12321')
})

app.listen(3000, () => {
    
    
    console.log('服务器已启用...')
}) 

Then let's analyze this requirement: this requirement is only for individual routes, so at this time, we have to choose to use local middleware. Obtain the url through the local middleware and judge whether the code parameter inside is 521. If it is 521, then we can continue to execute the routing rules; if not, return a password error.

Let's take a look at the code:

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

//声明中间件
let checkCodeMiddleware = (req, res, next) => {
    
    
    if(req.query.code === '521') {
    
    
        next();
    } else {
    
    
        res.send('暗号错误')
    }
}

app.get('/admin', checkCodeMiddleware, (req, res) => {
    
    
    res.end('12321')
})

app.get('/setting', checkCodeMiddleware, (req, res) => {
    
    
    res.end('12321')
})

app.listen(3000, () => {
    
    
    console.log('服务器已启用...')
}) 

==What needs to be noted here is that the registration of the local middleware is passed in the form of parameters in the subsequent call of the app. ==In order to prevent everyone from being confused, I will use a picture to illustrate the code sequence:
insert image description here
look at the picture above, when we send a request, we will first judge the URL of the request and select the response route. This is the first step; then , the second step is to execute the middleware, take the above example, if the code is 521, then execute next(), after next, execute the following routing rules, which is the third step, execute res.end; if not , that is to return 'cipher error'.

3.5 Static resource middleware (built-in)

Static resource middleware is a built-in middleware in the express framework, which is used to mount static resources, hang some static resources on the webpage, and display them after the correct url is accessed.

Next, let's review the two concepts of static resources and static resource directories.

Static resources refer to the html, css, js, pictures, etc. we use when writing code. These are all static resources.

The static resource directory can be understood as the root directory of the website.

Then look at the use of static resource middleware. Since it is a static resource mount, we first create a static resource directory, public, with an html file inside as a static resource:
insert image description here

insert image description here
Now let's use the built-in static resource middleware:

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

// 静态资源的中间件注册
app.use(express.static(__dirname + '/public'));

app.get('/admin', (req, res) => {
    
    
    res.send('222')
})

app.listen(3000, () => {
    
    
    console.log('服务器已经启动...')
})

Then, the static resources have been mounted to the server that comes with our computer:
insert image description here

insert image description here
Notes during use:
1. The index.html file is the resource opened by default;
2. If the static resource and the routing rule match ('/') at the same time, whoever matches first will respond (related to the code order);
3. Routing In response to dynamic resources, static resource middleware responds to static resources.

3.6 Get request body data middleware (external)

This middleware was written by someone else, and it is not built-in, so if we want to use it, we need to install and import it.

This middleware is named border-parser.

Installation import:
insert image description here
import border-parser package:
insert image description here
Middleware usage: There are two usage methods here, one is as global middleware; the other is as routing middleware. Routing middleware is more recommended here. Not every request needs to be processed by this middleware. Using routing middleware (local middleware) makes the project run more efficiently.

Next is the use of the middleware, which can be used in two ways:

//解析 JSON 格式的请求体的中间件
const jonParser = bodyParser.json()
//解析 queryString 格式请求体的中间件
const urlencodeParser = bodyParser.urlencoded({
    
     extended: false });

How to see which method is used to obtain the request body? In the payload of the request:
insert image description here
it can be seen that it is in querystring format.

If we want to use it, we can put it in the corresponding position.

Please see the full version of the code and comments below:

const express = require('express')
// 导入包
const bodyParser = require('body-parser')
const app = express()

// 使用body-parser中间件
//解析 JSON 格式的请求体的中间件
const jonParser = bodyParser.json()
//解析 queryString 格式请求体的中间件
const urlencodeParser = bodyParser.urlencoded({
    
     extended: false });

app.get('/login', (req, res) => {
    
    
    // 响应文件内容
    res.sendFile(__dirname + '/10._form.html')
})

app.post('/login', urlencodeParser, (req, res) => {
    
    
    console.log(req.body)//多一个body属性用来存放请求体
    res.send('获取用户的数据')
})

app.listen(3000, () => {
    
    
    console.log('服务器已启动...')
})

Form page code:

<!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>登录页面</title>
</head>
<body>
    <form action="http://127.0.0.1:3000/login" method="post">
        用户名:<input type="text" name="username"><br/>
        密码: <input type="password" name="password">
        <button>登录</button>
    </form>
</body>
</html>

Final result:
insert image description here
There is also a middleware application here, if you are interested, you can check it out:
This article will guide you to understand anti-leeching

Fourth, routing modularization

Modular programming increases code reusability and improves the independence of each piece of code.

Routing modularization can be simply understood as,Split routing

Next, I will use an example to explain the modularization of routing.

This is a complete code, with a foreground and a background, now let's split the front and back of this code:

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

//前台
app.get('/home', (req, res) => {
    
    
    res.send('前台首页')
})
app.get('/search', (req, res) => {
    
    
    res.send('内容搜索')
})

//后台
app.get('/admin', (req, res) => {
    
    
    res.send('后台首页')
})

app.get('/setting', (req, res) => {
    
    
    res.send('设置页面')
})

app.all('*', (req, res) => {
    
    
    res.send('<h1>404 Not Found</h1>')
})

app.listen(3000, () => {
    
    
    console.log('服务器已经运行...')
})

Let's split the front-end route first, and create a new file after to store the content:
insert image description here
import express and router in after:

//导入express
const express = require('express')
//创建路由对象
const router = express.Router()

Then put the route related to the foreground into the file and change app to router:

router.get('/home', (req, res) => {
    
    
    res.send('前台首页')
})
router.get('/search', (req, res) => {
    
    
    res.send('内容搜索')
})

Finally, it is exposed again, the following is the overall code:

//导入express
const express = require('express')
//创建路由对象
const router = express.Router()
//创建路由规则
router.get('/home', (req, res) => {
    
    
    res.send('前台首页')
})
router.get('/search', (req, res) => {
    
    
    res.send('内容搜索')
})

//暴露router
module.exports = router;

But it's not over yet, and it needs to be introduced and registered in all to be able to use it normally:

const express = require('express')
// 导入前台
const homeRouter = require('./after.js')
const app = express()
//注册
app.use(homeRouter)

Only in this way can it be used normally in the future:
insert image description here
then in the background, put the code directly, no more details:

const express = require('express')
const router = express.Router()
router.get('/admin', (req, res) => {
    
    
    res.send('后台首页')
})

router.get('/setting', (req, res) => {
    
    
    res.send('设置页面')
})

module.exports = router

Here's the overall code:

const express = require('express')
// 导入前台
const homeRouter = require('./after.js')
// 导入后台
const adminRouter = require('./before.js')
const app = express()
//注册
app.use(homeRouter).use(adminRouter)


app.all('*', (req, res) => {
    
    
    res.send('<h1>404 Not Found</h1>')
})

app.listen(3000, () => {
    
    
    console.log('服务器已经运行...')
})

Five, template engine

5.1 Template engine

A template engine is a technology that separates user interface and business data. (for separating html and js)

5.2 EJS

EJS is an advanced template engine.

Official Website: Official Website
Chinese Station: Chinese Station

The documentation is very clear and can be referred to if necessary.

Let me summarize here, there is one place that is very critical in EJS, that is

<% %>

The inside of this symbol is js code, and the outside of this symbol is the structure of html.

This is a point I have concluded. It is convenient for everyone to learn.

5.3 Combination of EJS and express framework

You can refer to the following code and comments:

const express = require('express')
const ejs = require('ejs')
const path = require('path')
const app = express()

//1.设置模板引擎,模板引擎有很多种,所以要设置是哪一种,我们用的ejs
app.set('view engine', 'ejs');
// 2.设置模板文件(具有模板语法内容的文件)存放位置,模板文件一定是后缀为ejs的,不然没办法找到
app.set('views', path.resolve(__dirname, './express'))

//3.render方法进行响应
app.get('/home', (req, res) => {
    
    
    // res.render('模板的文件名', '数据')
    let title = '123'
    res.render('view', {
    
    title})
})

app.listen(3000, () => {
    
    
    console.log('已经在服务器的 3000端口 运行...')
})

六,express-generator

6.1 Create an express project

In the previous content, express was written by us. The express-generator tool can help us create a standard structure of the express framework. We don't need to write some basic things.

To use this tool, you first need to install:

npm i express-generator -g

After installation, use the name to create an express project:

express -h '文件夹名'

The initialized project structure is as follows:
insert image description here
Next, let’s talk about the project running. Before the project runs, some initialization needs to be downloaded:

npm i

Then there is running:
insert image description here
As stated in the above file, the command to run is:

npm start

After doing the above, we can take a look at the effect:
insert image description here
it means the operation is successful.

6.2 Code structure

app.js是项目主文件;
views目录用于存放页面文件;
routes目录用于存放路由文件;
public用于存放静态文件;
bin中的www是项目的启动文件;

6.3 url prefix

In the app.js code, there is such a paragraph:

var usersRouter = require('./routes/users');
app.use('/users', usersRouter);

The second use corresponds to usersRouter in routes, let's look at the content of usersRouter:

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

/* GET users listing. */
router.get('/', function(req, res, next) {
    
    
  res.send('respond with a resource');
});

module.exports = router;

In this code, if you look at the get request alone, you will find that it is just a slash. But can this slash really show the content of send? Let's try:
insert image description here
no.

Reason: Need to add a prefix, the prefix is ​​users:

app.use('/users', usersRouter);

After adding the prefix, the corresponding content can be returned:
insert image description here

postscript

The above is the learning content of the express framework.

If you find it useful, you can like it, collect it and follow it. There will be related articles in the future and a message will be sent to you.

Guess you like

Origin blog.csdn.net/zxdznyy/article/details/130808126