Express.js tutorial

Express.js 教程展示了如何使用 Express 框架在 JavaScript 中创建简单的 Web 应用程序。

Express.js

Express.js 是一个用于 Node.js 的免费开源 Web 应用程序框架。 Express 是一个最小且灵活的 Web 应用程序框架,为 Web 和移动应用程序提供了一组强大的功能。

它是一个快速、独立且极简的 Web 框架。

Express.js 安装

我们安装 Express 框架。稍后,我们安装了其他包,包括 Lodash、sqlite3 和 Axios。

$ node -v
v18.2.0

我们使用 Node 版本 18.2.0。

$ npm init -y
$ npm i express

我们使用npm工具安装Express。

网址

统一资源定位器 (URL) 是对 Web 资源的引用,它指定了它在计算机网络上的位置和检索它的机制。网络资源是可以通过网络获取的任何数据,例如 HTML 文档、PDF 文件、PNG 图像、JSON 数据或纯文本。

通用 URL 具有以下形式:

scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]

[] 括号之间的部分是可选的。

Express.js 路由

路由 将 HTTP 动词(例如 GET、POST、PUT、DELETE)和处理程序函数的 URL 路径相关联。要创建路由,我们使用 Express 应用程序对象的函数。

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

});

这里我们将 GET 请求中发送的 / 路径映射到处理函数。该函数接收请求和响应对象作为参数。

要对路由进行分组并将它们分成模块,我们可以使用Routermiddleware。

Express.js 中间件

Express中间件是框架的核心。它位于请求-响应周期的中间。中间件是管道中请求对象和响应对象之间调用的一系列函数。 Express 是一个最小的框架。大多数功能都可以作为中间件功能使用。

中间件函数用于实现身份验证、CSRF 保护、日志记录或 cookie 处理等功能。它们不用于实现应用程序的业务逻辑。

use函数将指定的中间件函数挂载到指定路径。

Express.js GET 请求示例

get 函数使用指定的回调函数将 HTTP GET 请求路由到指定的路径。

const express = require('express');

const app = express();

app.get('/', (req, res) => res.send('Hello there!'));

app.listen(3000, () => console.log('Application started on port 3000'));

应用程序处理 GET 请求并向客户端发送一条短消息。

const express = require('express');

我们包括express包。

const app = express();

Express 应用程序已创建。

app.get('/', (req, res) => res.send('Hello there!'));

使用get 函数,我们将/ 路径映射到匿名函数,匿名函数将字符串发送回客户端。

app.listen(3000, () => console.log('Application started on port 3000'));

启动时,应用程序会侦听端口 3000。

$ node main.js
Application started on port 3000

我们在本地主机上启动应用程序。

$ curl localhost:3000
Hello there!

我们使用curl 命令创建一个请求。

Express.js HTTP 标头

请求对象还包括从客户端发送的请求标头。请求标头是 HTTP 标头,其中包含有关要获取的资源以及请求资源的客户端的更多信息。

const express = require('express');

const app = express();

app.get('/', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send(`The request IP is: ${req.ip}`);
});

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

该示例输出生成请求的客户端的 IP 地址。

$ curl localhost:3000
The request IP is: ::1

这是一个示例输出; ::1 是 IPv6 中的环回地址。

Express.js 查询参数

查询字符串是 URL 的一部分,用于为资源请求添加一些条件。它通常是一系列键/值对。它遵循路径并以 ? 字符开头。

const express = require('express');

const app = express();

app.get('/greet', (req, res) => {

    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    let name = req.query.name;
    let msg = `Hello ${name}`;
    res.send(msg);
});

app.listen(3000, () => console.log('Application started on port 3000'));

应用程序创建消息并将其发送到客户端。它使用来自 name 查询参数的值。

app.get('/greet', (req, res) => {

我们使用指定的回调函数将 HTTP GET 请求路由到指定的路径。回调函数接收两个参数:请求对象和响应对象。请求对象表示 HTTP 请求并具有请求查询字符串、参数、正文和 HTTP 标头的属性。

res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

我们设置响应内容类型和字符集。我们的输出将是明文。默认的内容类型是text/html

let name = req.query.name;

我们从请求查询属性中获取查询参数。它是一个包含路由中每个查询字符串参数的属性的对象。

let msg = `Hello ${name}`;

构建了一条消息。

res.send(msg);

消息被发送到客户端。

$ curl -i localhost:3000/greet?name=Lucia
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/plain; charset=utf-8
Content-Length: 11
ETag: W/"b-QOTbNGLVpb1ETGDcTt/rfpJV0wI"
Date: Tue, 21 Apr 2020 06:58:12 GMT
Connection: keep-alive

我们使用curl命令行工具向应用程序创建 GET 请求。使用 -i 选项,我们还包括响应头。

Express.js 路径参数

值可以通过查询参数或路径参数发送到网络应用程序。路径参数在冒号/:param 之后指定。

req.params 属性是一个包含映射到指定路由参数的属性的对象。

const express = require('express');

const app = express();

app.get('/show/:name/:age/', (req, res) => {

    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    let name = req.params.name;
    let age = req.params.age;
    let msg = `${name} is ${age} years old`;

    res.send(msg);
});

app.listen(3000, () => console.log('Application started on port 3000'));

应用程序向用户返回一条消息,其中包含发送的两个路径参数。

app.get('/show/:name/:age/', (req, res) => {

路径参数定义在路由路径中;参数的名称在冒号字符之后。

let name = req.params.name;
let age = req.params.age;

我们从req.params 对象中检索路径参数。

$ curl localhost:3000/show/Robert/24/
Robert is 24 years old

Express.js 路径模式匹配

可以在请求路径上使用正则表达式。这样我们就可以限制通过请求路径传递的值。

const express = require('express');

const app = express();

app.get('/city/:id([0-9]{1,5})', (req, res) => {

    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send(`id: ${req.params.id}`);
});

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

在示例中,我们将 Id 值限制为整数,具有 1 到 5 位数字。

$ curl localhost:3000/city/12345
id: 12345

这是 Id 12345 的输出。

表达 JSON

JSON 是一种轻量级数据交换格式。它易于人类阅读和机器解析和生成。 Web 应用程序经常使用和生成 JSON 数据。

res.json 函数发送一个 JSON 响应。参数可以是任何JSON类型,包括对象、数组、字符串、布尔值、数字或null。

$ npm i lodash

我们安装 Lodash 库。

const express = require('express');
const _ = require('lodash');

const app = express();

app.get('/movies', (req, res) => {

    res.set({ 'Content-Type': 'application/json; charset=utf-8' });

    let movies = { 1: 'Toy story', 2: 'The Raid', 3: 'Hero',
                4: 'Ip Man', 5: 'Kung Fu Panda' };

    let movie = _.sample(movies);

    res.json({movie});
});

app.listen(3000, () => console.log('Application started on port 3000'));

该示例从movies 对象中选取随机电影。电影以 JSON 格式返回。

res.set({ 'Content-Type': 'application/json; charset=utf-8' });

我们为 JSON 数据设置内容类型。

let movies = { 1: 'Toy story', 2: 'The Raid', 3: 'Hero',
            4: 'Ip Man', 5: 'Kung Fu Panda' };

我们在 JS 对象中有几部电影。

let movie = _.sample(movies);

使用 Lodash _sample 方法,我们随机选择一部电影。

res.json({movie});

选择的电影以JSON格式发送给客户端。

$ curl localhost:3000/movies
{"movie":"Toy story"}
$ curl localhost:3000/movies
{"movie":"Kung Fu Panda"}$
$ curl localhost:3000/movies
{"movie":"Kung Fu Panda"}

Express 正文解析器

body-parser 是一个 Node 请求主体解析中间件。它在我们的处理程序之前在中间件中解析传入的请求主体。数据在req.body 属性下可用。

对于这个例子,我们需要安装axios包。

$ npm i axios

Axios 是用于浏览器和 Node.js 的基于承诺的 HTTP 客户端

const express = require("express");

const app = express();
app.use(express.json());

app.post('/info', (req, res) => {

    console.log(req.body);

    res.json(req.body);
});

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

在示例中,我们解析 JSON 主体。

app.use(express.json());

这里我们应用body parser中间件来解析请求体中的JSON数据。

res.json(req.body);

我们将解析后的数据以JSON格式返回给客户端。

const axios = require('axios');


async function makePostRequest() {

    params = {
        first_name: 'John',
        last_name: 'Doe',
        email: 'gardener'
      }

    let res = await axios.post('http://localhost:3000/info/', params);

    console.log(`Status code: ${res.status}`);
    console.log(`Status text: ${res.statusText}`);
    console.log(`Request method: ${res.request.method}`);
    console.log(`Path: ${res.request.path}`);

    console.log(res.data);
}

makePostRequest();

使用 Axios 库,我们向 Express 应用程序发出 POST 请求。

$ node post-request.js
Status code: 200
Status text: OK
Request method: POST
Path: /info/
{ first_name: 'John', last_name: 'Doe', email: 'gardener' }

快递单

HTTP POST 方法向服务器发送数据。它通常在上传文件或提交完整的 Web 表单时使用。从表单发送的数据存储在请求的正文中。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Form</title>
</head>
<body>

    <form action="message" method="post">

        <div>
            <label>Name:</label>
            <input type="text" name="name">
        </div>

        <div>
            <label>Message</label>
            <input type="text" name="message">
        </div>

        <button type="submit">Send</button>

    </form>

</body>
</html>

我们有一个包含两个输入字段的表单:namemessage

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

const app = express();
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));

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

    res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

app.post('/message', (req, res) => {

    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    let name = req.body.name;
    let message = req.body.message;
    let output = `${name} says: ${message}`;

    res.send(output);
});


app.listen(3000, () => {

    console.log('Application started on port 3000');
})

我们在应用程序中有两条路线。 / 路径将表单带给用户。该函数只是发送包含表单的静态 HTML 文件。 /message 路径处理表单并根据发布的数据构建消息。

app.use(express.urlencoded({ extended: true }));

我们应用urlencoded中间件来处理表单。中间件使用urlencoded payloads解析传入的请求。application/x-www-form-urlencoded内容类型是默认的。(扩展选项选择特定的库来解析数据。)

let name = req.body.name;
let message = req.body.message;
let output = `${name} says: ${message}`;

我们从请求正文中获取两个参数并构建输出。

res.send(output);

输出被发送到客户端。

快递发送文件

sendFile 函数在给定路径传输文件。图像显示在浏览器中。 download函数传输图像;该图像由浏览器作为附件提供。

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

const app = express();


app.get('/file', (req, res) => {

    res.set({ 'Content-Type': 'image/jpeg' });

    let file = path.join(__dirname, 'img/book.jpg');

    // res.sendFile(file);
    res.download(file, 'book-image.jpg');
});


app.listen(3000, () => {

    console.log('Application started on port 3000');
})

该示例向客户端发送图像。请注意,由于浏览器正在执行缓存,因此我们可能看不到这两种方法之间的区别。在这种情况下,我们可以打开一个隐私窗口。

res.set({ 'Content-Type': 'image/jpeg' });

我们设置合适的内容类型。

let file = path.join(__dirname, 'img/book.jpg');

我们指定图片的路径。

表达静态文件

静态文件是不会改变的文件。它们包括 CSS 文件、JavaScript 文件和图像;也包括不包含模板指令的 HTML 文件。

为了处理静态文件,我们使用内置的static 中间件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

    <p>
        This is home page
    </p>

</body>
</html>

这是主页。这是一个静态 HTML 文件的示例。

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

const app = express();

app.use(express.static('public'));

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

    res.sendFile(path.join(__dirname, 'public/index.html'));
});

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

该示例显示主页的简单静态 HTML 文件。

app.use(express.static('public'));

我们使用静态中间件;静态文件存储在public 目录中。

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

    res.sendFile(path.join(__dirname, 'public/index.html'));
});

sendFile 函数在给定路径传输文件。

Express 图标

网站图标,也称为网站图标,是与特定网站或网页相关联的小图标。要在 Express 应用程序中显示网站图标,我们可以使用 express-favicon 中间件。

$ npm i express-favicon

我们安装包。

$ ls public/images/
favicon.ico

我们在favicon目录中有public/images

const express = require('express');
const path = require('path');
const favicon = require('express-favicon');

const app = express();

app.use(favicon(path.join(__dirname, 'public', 'images', 'favicon.ico')));

app.get('/', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('Home page');
});

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

该示例显示一个图标。

app.use(favicon(path.join(__dirname, 'public', 'images', 'favicon.ico')));

我们使用use 函数应用中间件函数。该图标位于 public/images 目录中。

表达自定义 404 错误信息

HTTP 404、404 Not Found、404、Page Not Found 错误消息是网络通信中使用的超文本传输​​协议 (HTTP) 标准响应代码。它表示浏览器能够与给定服务器通信,但服务器找不到请求的资源。

Express 提供基本的 404 消息。在以下示例中,我们创建了自定义的。

const express = require('express');

const app = express();


app.get('/', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('Home page');
});

app.get('/about', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('About page');
});

app.get('/contact', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('Contact page');
});


app.use((req, res) => {

    res.statusCode = 404;
    res.end("404 - page not found");
});

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

在示例中,我们为 404 not found 错误注册了一个错误处理函数。它显示了 404.html 文件。

app.use((req, res) => {

    res.statusCode = 404;
    res.end("404 - page not found");
});

我们设置状态码并完成响应过程。错误处理的映射在所有其他映射之后。

Express Router 中间件

基本路由使用应用程序对象的路由方法执行,例如getpostputheaddelete

可以使用Routermiddleware 将路由分组并分成模块。

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

router.get('/', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('Home page');
});

router.get('/about', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('About page');
});

router.get('/contact', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('Contact page');
});

module.exports = router;

routes.js模块中有3条路由,路由都绑定到Router中间件,中间件对外暴露。

const express = require('express');
const routes = require('./routes');

const app = express();

app.use(routes);

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

我们包含路由并使用use 将它们应用于应用程序。

Express – 使用模板引擎

模板引擎或模板处理器是一个库,旨在将模板与数据模型结合起来以生成文档。模板引擎用于生成大量电子邮件、源代码预处理或生成动态 HTML 页面。

Express 可以使用许多模板引擎;例如 Liquid、Nunjucks、Pug 或 EJS。

Liquid 是一个 JavaScript 模板引擎,由 Shopify 创建。 Liquidfiles 的扩展名为.liquid;它们是 HTML 和 Liquid 结构等静态数据的混合体。在 Liquid.js 教程中了解有关 Liquid 的更多信息。

$ npm i liquidjs

我们安装了 Liquid 模板引擎。

在 Liquid 中,我们使用双大括号分隔符 {{ }} 表示输出,使用大括号百分比分隔符 {% %} 表示逻辑。

{% if user != null %}
  Hello {{ user.name }}
{% endif %}

此代码是示例 Liquid 语法。

const express = require('express');
const path = require('path');
const { Liquid } = require('liquidjs');

const app = express();
const engine = new Liquid();

app.engine('liquid', engine.express());
app.set('views', path.resolve(__dirname, 'views'));
app.set('view engine', 'liquid');

app.get('/today', (req, res) => {

    let today = new Date();
    res.render('show_date', {now: today});
});

app.use((req, res) => {

    res.statusCode = 404;
    res.end("404 - page not found");
});

app.listen(3000, () => {

    console.log('Application started on port 3000');
});

在示例中,我们从路径参数中读取一个值,并将其发送到show_date.liquid模板文件进行处理。

app.engine('liquid', engine.express());
app.set('views', path.resolve(__dirname, 'views'));
app.set('view engine', 'liquid');

我们设置了 Liquid 模板引擎。模板文件位于 views 目录中。

res.render('show_date', {now: today});

render 函数呈现一个视图并将呈现的 HTML 字符串发送到客户端。第一个参数是视图名称(不带扩展名);第二个参数是locals 对象,其属性定义了视图的局部变量。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Show date</title>
</head>
<body>

    <p>
        Today is {{ now }}
    </p>

</body>
</html>

这是show_date.liquid 模板文件。该模板由静态数据和动态数据组成。

<p>
    Today is {{ now }}
</p>

使用{{}}语法,我们输出传递给模板的now变量的值。

$ curl localhost:3000/today
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Show date</title>
</head>
<body>

    <p>
        Today is Tue Jun 28 2022 11:15:15 GMT+0200 (Central European Summer Time)
    </p>

</body>
</html>

Express SQLite 示例

在下面的示例中,我们从 SQLite 数据库发送数据。SQLite 是一个基于文件的关系数据库引擎。

$ npm install sqlite3

我们使用sqlite3包。

app-sqlite.js
data
  cities.sql
  test.db

这是项目结构。

BEGIN TRANSACTION;
DROP TABLE IF EXISTS cities;

CREATE TABLE cities(id INTEGER PRIMARY KEY, name TEXT, population INTEGER);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
COMMIT;

我们使用这些数据。

$ cd data
$ sqlite3 test.db
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> .read cities.sql
sqlite> select * from cities;
1|Bratislava|432000
2|Budapest|1759000
3|Prague|1280000
4|Warsaw|1748000
5|Los Angeles|3971000
6|New York|8550000
7|Edinburgh|464000
8|Berlin|3671000

我们将数据加载到test.db 数据库中。

const express = require('express');
const sqlite3 = require('sqlite3').verbose();

const app = express();
const db = new sqlite3.Database('data/test.db');

app.get('/', (req, res) => {
    res.set({ 'Content-Type': 'text/plain; charset=utf-8' });

    res.send('Home page');
});

app.get('/cities', (req, res) => {

    const sql = 'select * from cities';
    const params = [];

    db.all(sql, params, (err, rows) => {

        if (err) {

          res.status(400).json({'error': err.message});
          return;
        }

        if (!rows) {

          res.status(204).json({'error': 'No cities found'});
          return;
        }

        res.json({
            'message':'success',
            'data':rows
        });
    });
});

app.get('/city/:id', (req, res) => {

    const sql = 'select * from cities where id = ?';
    const params = [req.params.id];

    db.get(sql, params, (err, row) => {

        if (err) {

          res.status(400).json({'error':err.message});
          return;
        }

        if (!row) {

          res.status(204).json({'error': 'City not found'});
          return;
        }

        res.json({
            'message':'success',
            'data':row
        });
    });
});

const server = app.listen(3000, () => {

    console.log('Application started on port 3000');
});

process.on('SIGINT', () => {

    db.close((err) => {

        console.log('Application terminating');

        if (err) {
            console.error(err.message);
        }
          console.log('Closing the database connection.');
        });

    server.close();
});

应用中有3个路由。一个用于主页,另一个用于所有城市,第三个用于特定城市。城市以 JSON 格式返回。

const sqlite3 = require('sqlite3').verbose();

我们包含sqlite3 包。 verbose 函数生成调试信息。

const db = new sqlite3.Database('data/test.db');

我们连接到数据库文件。

app.get('/cities', (req, res) => {

    const sql = 'select * from cities';
    const params = [];
...

对于 /cities 路由,我们从数据库中获取所有行并将它们作为 JSON 数据发送到客户端。没有参数传递给 SQL 语句。

db.all(sql, params, (err, rows) => {

all 函数使用指定的参数运行 SQL 查询,然后使用所有结果行调用回调。

if (err) {

  res.status(400).json({'error': err.message});
  return;
}

如果有错误,我们发送 400 状态码并返回。

if (!rows) {

  res.status(204).json({'error': 'No cities found'});
  return;
}

如果没有找到数据,我们会发送 204 No content 状态码。

res.json({
    'message':'success',
    'data':rows
});

我们使用 json 函数发送一个 JSON 响应,其中包含选定的行。

app.get('/city/:id', (req, res) => {

    const sql = 'select * from cities where id = ?';
    const params = [req.params.id];
...

在这条路线中,我们搜索具有特定 Id 的城市。 params 数组包含来自请求路径参数的 Id。

db.get(sql, params, (err, row) => {

get 函数使用指定的参数运行 SQL 查询,然后使用第一个结果行调用回调。

res.json({
    'message':'success',
    'data':row
});

所选行以 JSON 格式发送到客户端。

$ curl localhost:3000/cities
{"message":"success","data":[{"id":1,"name":"Bratislava","population":432000},
{"id":2,"name":"Budapest","population":1759000},
{"id":3,"name":"Prague","population":1280000},
{"id":4,"name":"Warsaw","population":1748000},
{"id":5,"name":"Los Angeles","population":3971000},
{"id":6,"name":"New York","population":8550000},
{"id":7,"name":"Edinburgh","population":464000},
{"id":8,"name":"Berlin","population":3671000}]}

在本文中,我们介绍了 Express.js 网络框架。

列出所有 JavaScript 教程。

赞(0) 打赏

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏