Getting started with node basics, npm and packages, Express middleware

Node.js

1 Introduction to Node.js

Node.js is a JavaScript runtime environment based on the Chrome V8 engine.

The browser is the front-end runtime environment for JavaScript;

Node.js is the back-end runtime environment for JavaScript;

The built-in APIs of browsers such as DOM and BOM cannot be called in Node.js.

JavaScript learning path in the browser:
JavaScript basic syntax + browser built-in API (DOM + BOM) + third-party libraries (jQuery, art-template, etc.)

Node.js learning path:
JavaScript basic syntax + Node.js built-in API modules (fs, path, http, etc.) + third-party API modules (express, mysql, etc.)

2 fs file system module

2.1 What is the fs file system module

fs 模块It is a module officially provided by Node.js for manipulating files, providing a series of methods and properties.

For example:

fs.readFile() method, used to 读取specify the contents of the file

The fs.writeFile() method is used to write the specified file 写入content

Import fs:

const fs = require('fs');

2.2 读取Specify the contents of the file

1 fs.readFile() syntax format.

fs.readFile( path[,options], callback);

Interpretation of parameters: Parameters enclosed in square brackets [] are optional parameters.

Parameter 1: Mandatory parameter, string, representation 文件的路径.

Parameter 2: Optional parameter, indicating what 编码格式to read the file with.

Parameter 3: Required parameter, after the file is read, it will be obtained through the callback function 读取的结果.

2 fs.readFile() example code.

Read the content of the specified file in utf8 encoding format, and print the values ​​of err and dataStr.

// 1 引入 fs 模块
const fs = require("fs");

// 2 调用 fs.readFile() 方法读取文件
fs.readFile("./files/1.txt", "utf8", (err, res) => {
    
    
  console.log("err", err); // 失败的结果
  console.log("res", res); // 成功的返回值
});

// 如果读取成功,则 err 的值为 null
// 如果读取失败,则 err 的值为 错误对象,res 的值为 undefined

写入2.3 Add content to the specified file

1 fs.writeFile() syntax format.

fs.writeFile(file, data[, options], callback)

Interpretation of parameters:

Parameter 1: Required parameter, you need to specify a string of file path, indicating the storage path of the file. (If the file corresponding to the path does not exist, a new file will be created to write the content.)

Parameter 2: Mandatory parameter, means yes 写入的内容.

Parameter 3: Optional parameter, which indicates the format to write the file content in, and the default value is utf8.

Parameter 4: Mandatory parameter, the callback function after the file is written

2 fs.writeFile() sample code.

// 1 引入 fs 模块
const fs = require("fs");

// 2 调用 fs.writeFile() 方法读取文件
fs.writeFile("./files/2.txt", "222txt内容", (err) => {
    
    
  console.log("err", err);
});

// 如果写入成功,则 err 的值等于 null  
// 如果写入失败,则 err 的值等于一个 错误对象

2.4 Case

Read files, process data, write files.

// 1 引入 fs 模块
const fs = require("fs");

// 2 调用 fs.readFile() 方法读取文件
fs.readFile("./files/成绩.txt", "utf8", (err, res) => {
    
    
  // 3 判断是否读取成功
  if (err) {
    
    
    return console.log("读取文件失败!", err);
  }

  // 4 读取文件成功后
  // 4.1 先把成绩的数据,按照空格进行分割
  const data = res.split(" ");

  // 4.2 将 = 替换 :
  const data2 = data.map((item) => item.replace("=", ":"));

  // 4.3 再将新数组中的每一项,进行合并,得到新的字符串 \r\n 表示换行的意思
  const str = data2.join("\r\n");

  //   5 调用 fs.writeFile() 方法,把处理完的数据写入到新的文件中
  fs.writeFile("./files/成绩2.txt", str, (err) => {
    
    
    if (err) {
    
    
      return console.log("写入文件失败!", err);
    }
    console.log("写入成功!");
  });
});

2.5 fs module - path dynamic splicing problem

When using the fs module to operate files, if the provided operation path starts with ./ or .../ 相对路径, it is easy to cause path dynamic splicing errors.

Reason: When the code is running, it will dynamically splice out the full path of the operated file based on the directory where the node command is executed.

Solution: When using the fs module to operate files, 直接提供完整的路径do not provide a relative path starting with ./ or .../, so as to prevent the problem of dynamic path splicing.

That is to start writing from the drive letter.

const fs = require("fs");

fs.readFile("C:\\Users\\blank\\Desktop\\2022node\\代码笔记\\files\\1.txt", "utf8", (err, res) => {
    
    
  console.log("err", err);
  console.log("res", res);
});

Disadvantages: poor portability, not conducive to maintenance.

Better solution: __dirnameIndicate the directory where the current file is located.

const fs = require("fs");

fs.readFile(__dirname + "/files/1.txt", "utf8", (err, res) => {
    
    
  console.log("err", err);
  console.log("res", res);
});

3 path path module

3.1 What is the path path module

The path module is an official 处理路径module provided by Node.js for use. It provides a series of methods and attributes to meet the user's processing requirements for paths.

For example:

path.join() method, used to combine多个路径片段拼接成一个完整的路径字符串

The path.basename() method is used to parse the file name from the path string

Import the path module:

const path = require('path');

3.2 Path splicing path.join()

path.join()The method can concatenate multiple path fragments into a complete path string.

Grammar format:

path.join([...paths]);

Interpretation of parameters:

...paths sequence of path fragments, can be any number

return value:

Code example:

const path = require("path");
const fs = require("fs");

// 注意:../ 会抵消前面的路径
const pathStr = path.join("/a", "/b/c", "../", "./d", "e");
console.log(pathStr); // 一组 "../" 即抵消前面一个路径 \a\b\d\e

const pathStr2 = path.join("/a", "/b/c", "../../", "./d", "e");
console.log(pathStr2); // 两组 "../" 即抵消前面两个个路径 \a\d\e

// fs.readFile(__dirname + "./files/1.txt", "utf8", (err, res) => {
    
    

fs.readFile(path.join(__dirname, "/files/1.txt"), "utf8", (err, res) => {
    
    
  console.log("err", err);
  console.log("res", res);
});

3.3 Get the file name in the path path.basename()

path.basename()The last part of the path can be obtained, and the file name in the path is often obtained by this method.

The syntax format is as follows:

path.basename(path[, ext]);

Interpretation of parameters:

path is a required parameter, a string representing a path

ext Optional parameter, indicating the file extension. If the second parameter is passed in, the return value does not include the extension

Returns: indicates the last part in the path

Code example:

const path = require("path");

// 定义文件的存放路径
const fpath = '/a/b/c/index.html'

const fullName = path.basename(fpath);
console.log('包含扩展名',fullName); // 包含扩展名 index.html

const nameWithoutExt = path.basename(fpath,'.html');
console.log('不包含扩展名',nameWithoutExt); // 不包含扩展名 index

3.4 Get the extension in the path path.extname()

path.extname()method, you can get the path 扩展名部分.

The syntax format is as follows:

path.extname(path)

Interpretation of parameters:

path is a required parameter, a string representing a path

Returns: Returns the obtained extension string

Example code:

const path = require("path");

// 定义文件的存放路径
const fpath = '/a/b/c/index.html'

const fext = path.extname(fpath);
console.log('文件扩展名',fext); // .html

3.5 Comprehensive case


4 http modules

4.1 What is the http module

In a network node, the computer responsible for consuming resources is called a client;
the computer responsible for providing network resources externally is called a server.

http 模块It is a module officially 创建 web 服务器provided . Through http.createServer()the methods , an ordinary computer can be conveniently turned into a Web server to provide Web resource services to the outside world.

Import the http module:

const http = require('http');

4.2 Understand the role of the http module

The difference between a server and an ordinary computer is that web server software , such as IIS, Apache, etc., is installed on the server . By installing these server software, an ordinary computer can be turned into a web server.

In Node.js, we don't need to use third-party web server software such as IIS and Apache. Because we can easily write a server software by hand with a few lines of simple code based on the http module provided by Node.js , so as to provide web services to the outside world .

4.3 Server related concepts

1 IP address

An IP address is the unique address of each computer on the Internet, so the IP address is unique. If a "personal computer" is compared to "a phone", then an "IP address" is equivalent to a "telephone number". Only when the other party's IP address is known can data communication be performed with the corresponding computer.

The format of the IP address: usually in the form of (abcd) in "dotted decimal", where a, b, c, d are all decimal integers between 0 and 255. For example: IP address expressed in dotted decimal (192.168.1.1)

Note:
①Every web server in the Internet has its own IP address . For example, you can run the ping www.baidu.com command in a Windows terminal to view the IP address of the Baidu server.

② During the development period, your computer is both a server and a client. For the convenience of testing, you can enter the IP address 127.0.0.1 in your browser to access your computer as a server .

2 Domain names and domain name servers

Although the IP address can uniquely mark the computer on the network, the IP address is a long series of numbers, which is not intuitive and easy to remember, so people invented another set of character-based address schemes, the so-called domain names (Domain Names) . ) address .

There is a one-to-one correspondence between IP addresses and domain names , and this correspondence is stored in a computer called a domain name server ( DNS , Domain name server). Users only need to access the corresponding server through the easy-to-remember domain name, and the corresponding conversion work is realized by the domain name server. Therefore, a domain name server is a server that provides conversion services between IP addresses and domain names.

Note:
① Computers on the Internet can also work normally by simply using the IP address. But with the blessing of domain names, the Internet world can become more convenient.
② During the development and testing period, the domain name corresponding to 127.0.0.1 is localhost , they all represent our own computer, and there is no difference in the use effect. ( 127.0.0.1 === localhost )

3 port number

The port number in the computer is like the house number in real life. Through the house number, the takeaway brother can accurately deliver the takeaway to you in many rooms in the entire building.

By the same token, hundreds or thousands of web services can run on a single computer. Each web service corresponds to a unique port number. The network request sent by the client can be accurately handed over to the corresponding web service for processing through the port number .

Note:
① Each port number cannot be occupied by multiple web services at the same time.
② In practical applications, port 80 in the URL can be omitted .

4.4 Create a web server

1 basic steps:

① Import the http module
② Create a web server instance
③ Bind the request event to the server instance and listen to the client's request
④ Start the server

// 1 导入 http 模块
const http = require("http");

// 2 创建 web 服务器实例
const server = http.createServer();

// 3 为服务器实例绑定 request 事件,监听客户端的请求
server.on("request", function (req, res) {
    
    
  console.log("Someone visit our web server.");
});

// 4 启动服务器
server.listen(8080, function () {
    
    
  console.log("server runing at http://127.0.0.1:8080");
});

2 reqrequest object

As long as the server receives the client's request, it will call the request event processing function bound to the server through server.on() .

If you want to access data or properties related to the client in the event handler, you can use the following methods:

// req 是请求对象,包含了与客户端相关的数据和属性
server.on("request", (req) => {
    
    
  const {
    
     url, method } = req;
  console.log('客户端请求的 URL 地址',url);
  console.log('客户端的 method 请求类型',method);
});

3 resresponse object

In the server's request event handler, if you want to access server-related data or attributes , you can use the following methods:

res.end()

server.on("request", (req, res) => {
    
    
  const {
    
     url, method } = req;
  const str = `客户端请求的URL地址为:${
      
      url},客户端的请求类型为:${
      
      method}`;
  
  res.end(str); // res.end() 方法的作用:向客户端发送指定的内容,并结束这次请求的处理过程。
});

4 Solve the problem of Chinese garbled characters

When calling the res.end() method to send Chinese content to the client, there will be garbled characters. At this time, you need to manually set the encoding format of the content:

res.setHeader(“Content-Type”, “text/html; charset=utf-8”);

server.on("request", (req, res) => {
    
    
  const {
    
     url, method } = req;
  const str = `客户端请求的URL地址为:${
      
      url},客户端的请求类型为:${
      
      method}`;

  // 为了防止中文显示乱码的问题,需要设置响应头 Content-Type 的值为 text/html;charset=utf-8
  res.setHeader("Content-Type", "text/html; charset=utf-8"); // 固定写法
  res.end(str); 
});

5 Respond to different html content according to different urls

Core implementation steps:
① Obtain the requested url address
② Set the default response content to 404 Not found
③ Determine whether the user requested is the / or /index.html home page
④ Determine whether the user requested the /about.html about page
⑤ Set Content -Type response header to prevent Chinese garbled characters
⑥ Use res.end() to respond the content to the client

const http = require("http");
const server = http.createServer();

server.on("request", function (req, res) {
    
    
  // 1 获取请求的 url 地址
  const {
    
     url } = req;
  // 2 设置默认的内容为 404 Not Found
  let content = "<h1>404 Not Found!</h1>";

  // 3 根据 url 确定要显示的内容
  if (url === "/" || url === "/index.html") {
    
    
    content = "<h1>index页面</h1>";
  } else if (url === "/about.html") {
    
    
    content = "<h1>about页面</h1>";
  }

  res.setHeader("Content-Type", "text/html; charset=utf-8");
  res.end(content);
});

server.listen(80, function () {
    
    
  console.log("server runing at http://127.0.0.1");
});


5 Modular

5.1 The concept of modularity

1 What is Modularity

Modularization in the programming field is to follow fixed rules and split a large file into multiple small modules that are independent and interdependent. That is, a complex problem is divided into small modules for processing.

The benefits of modular splitting code:

Improved code reusability

Improved code maintainability

On-demand loading can be achieved

2 Modular Specifications

The modular specification is the rules that need to be followed when the code is modularized and combined.

For example: what grammatical format is used to refer to modules, and what grammatical format is used to expose members in modules

Benefits of Modular Specifications:

Everyone complies with the same modular specification to write code, which reduces communication costs and greatly facilitates mutual calls between modules, benefiting others and themselves.

5.2 Modularity in node.js

1 Classification of modularity in node.js

In node.js, modules are divided into three categories according to different sources of modules, namely:

Built-in modules: provided by node.js official website, such as fs, path, http, etc.

Custom module: Every .js file created by the user is a custom module

Third-party modules: modules developed by third parties are neither official built-in modules nor user-created custom modules, and need to be downloaded before use

2 load module

Using the powerful require()method , you can load the required modules for use. For example:

// 1 加载内置的 fs 模块
const fs = require('fs');

// 2 加载用户定义的自定义模块(需要通过路径) 
const custom = require('./custom.js');
const custom = require('./custom');//可以省略.js后缀名

// 3 加载第三方模块 
const moment = require('moment');

Note: When using the require() method to load other modules, the code in the loaded module will be executed.

3 Module scope in node.js

Similar to function scope, variables, methods and other members defined in custom modules can only be accessed within the current module. This kind of module-level access restriction is called module scope .

The benefits of module scope: prevent the problem of global variable pollution.

4 Members in shared module scope outward

(1) module object

There is a module object in each .js custom module, which stores information related to the current module.

Module {
    
    
  id: '.',
  path: 'C:\\Users\\blank\\Desktop\\2022node\\代码笔记',
  exports: {
    
    },
  filename: 'C:\\Users\\blank\\Desktop\\2022node\\代码笔记\\10 module.js',
  loaded: false,
  children: [],
  paths: [
    'C:\\Users\\blank\\Desktop\\2022node\\代码笔记\\node_modules',
    'C:\\Users\\blank\\Desktop\\2022node\\node_modules',
    'C:\\Users\\blank\\Desktop\\node_modules',
    'C:\\Users\\blank\\node_modules',
    'C:\\Users\\node_modules',
    'C:\\node_modules'
  ]
}
(2) module.exports object

In a custom module, use module.exportsOutward Shared Members for external use. By default module.exports is equal to an empty object.

When the outside world uses require()the method to import a custom module, what is obtained is the object pointed to by module.exports.

Custom components:

// 在一个自定义模块中,默认情况下,module.exports === {}

// 向 module.exports 对象上挂载 username 属性
module.exports.username = "小徐";

// 向 module.exports 对象上挂载 sayHello 方法
module.exports.sayHello = function () {
    
    
  console.log("Hello!");
};

const age = 24;
module.exports.age = age;

External receiving components:

// 在外界使用 require 导入一个自定义的模块的时候,得到的成员就是,那个模块中
// 通过 module.exports 指向的那个对象

const zhidingyi = require("./11 自定义模块");

console.log(zhidingyi);// { username: '小徐', sayHello: [Function (anonymous)], age: 24 }

(3) Points to note when sharing members

When using the require() method to import a module, the result of the import is always based on the object pointed to by module.exports.

// 在一个自定义模块中,默认情况下,module.exports === {}

// 向 module.exports 对象上挂载 username 属性
module.exports.username = "小徐";

// 向 module.exports 对象上挂载 sayHello 方法
module.exports.sayHello = function () {
    
    
  console.log("Hello!");
};

const age = 24;
module.exports.age = age;

// 让 module.exports 指向一个全新的对象。
// 也就是在该文件中,最后输出的对象是下面最后指向的对象
module.exports = {
    
    
    nikename:'香香',
    sayHi(){
    
    
        console.log('Hi! xx');
    }
}

(4) exports object

Since the word module.export is more complicated to write, in order to simplify the shared code, node provides exportsthe object .

By default, exports and module.exports point to the same object .

The final shared result is still based on the object pointed to by module.exports.

module.exports.username = "小徐";

exports.username = "小徐";

// 二者作用相同
(5) Misuse of exports and module.exports

Note that when you require() a module, you will always get the object pointed to by module.exports .

export.username = 'xiaoxu';
module.exports = {
    
    
    gender: 'nan',
    age: 22
}

// 最终输出的对象是 
{
    
     
    gender: 'nan',
	age: 22
}
module.exports.username = 'xiaoxu';
export = {
    
    
    gender: 'nan',
    age: 22
}

// 最终输出的对象是 
{
    
     
    username: 'xiaoxu',
}
exports.username = 'xiaoxu';
module.exports.gender = 'nan';

// 最终输出的对象是 
{
    
     
    username: 'xiaoxu',
	gender: 'nan'
}
export = {
    
    
    username: 'xiaoxu',
    gender: 'nan',
}
module.exports = exports;
module.exports.age = 22

// 最终输出的对象是 
{
    
     
    username: 'xiaoxu',
	gender: 'nan',
    age: 22
}

Note: To prevent confusion, try not to use both exports and module.exports in the same module

5 Modularity Specifications in Node.js

node.js follows the CommonJS modular specification, and CommonJS stipulates the characteristics of modules and the interdependence between modules .

CommonJS states:

(1) Inside each module, the module variable represents the current module;

(2) The module variable is an object, and its exports attribute (that is, module.exports) is an external interface;

(3) Loading a module is actually loading the module.exports property of the target module. The require() method is used to load modules.


6 npm and packages

6.1 package

1 What is a package

Third-party modules in node.js are called .

2 sources of packs

Unlike built-in modules and custom modules in Node.js, packages are developed by third-party individuals or teams and are free for everyone to use.

Note : The packages in Node.js are all free and open source , and you can download and use them for free without paying.

3 Why do you need packages

Since the built-in modules of Node.js only provide some low-level APIs, the efficiency of project development based on built-in modules is very low.

Packages are encapsulated based on built-in modules , providing a more advanced and convenient API, which greatly improves development efficiency.

The relationship between packages and built-in modules is similar to the relationship between jQuery and browser built-in APIs.

4 Where to download packages from

There is an IT company abroad called npm, Inc. This company has a very famous website: https://www.npmjs.com/, which is the world's largest package sharing platform , you can search from this website Any bag you need, as long as you have enough patience!

So far, more than 11 million developers around the world have developed and shared more than 1.2 million packages for our use through this package sharing platform.

npm, Inc. provides a server with the address https://registry.npmjs.org/ to share all packages externally, and we can download the packages we need from this server.

Notice:

  • Search for the packages you need from the https://www.npmjs.com/ website

  • Download the packages you need from the https://registry.npmjs.org/ server

5 How to download the package

npm, Inc. provides a package management tool. We can use this package management tool to download the required packages from the https://registry.npmjs.org/ server for local use.

The name of this package management tool is Node Package Manager (npm package management tool for short), and this package management tool is installed on the user's computer along with the Node.js installation package.

You can execute the npm -v command in the terminal to check the version number of the npm package management tool installed on your computer

6.2 npm

1 command to install the specified package

npm install 包的完整名称

// 简写
npm i 包的完整名称

2 What files are added after the initial packaging

After the initial packaging is completed, there will be a folder called node_modules and a configuration file package-lock.json under the project folder.

in:

node_modules文件夹Used to store all packages installed into the project . When require() imports a third-party package, it looks for and loads the package from this directory.

package-lock.json配置文件It is used to record the download information of each package in the node_modules directory , such as package name, version number, download address, etc.

Note: Programmers should not manually modify any code in node_modules or package-lock.json files, the npm package management tool will automatically maintain them.

3 Install the specified version of the package

By default, when using the npm install command to install a package, the latest version of the package is automatically installed . If you need to install a specific version of the package, you can specify the specific version through the @ symbol after the package name , for example:

npm i moment@2.22.2

4 Semantic Versioning Specifications for Packages

The version number of the package is defined in the form of "dotted decimal", with a total of three digits, such as 2.24.0

The meaning of each digit is as follows:

1st digit: large version

2nd digit: function version

3rd digit: Bug fix version

The rule of version number promotion: as long as the previous version number increases, the subsequent version number will be reset to zero.

6.3 Package management configuration file

Npm stipulates that in the project root directory , a package management configuration file called must be provided .package.json

Used to record some configuration information related to the project. For example:

  • The project's name, version number, description, etc.

  • Which packages are used in the project

  • Which packages are only used during development

  • Those packages are required for both development and deployment

1 The problem of multi-person collaboration

Problems encountered in multi-person collaboration: the third-party package is too large , and it is inconvenient to share project source code among team members.

Solution: Eliminate node_modules when sharing

2 How to record which packages are installed in a project

In the project root directory, create a file called package.json 的配置文件, which can be used to record which packages are installed in the project .

This makes it easy to share the source code of the project among team members after removing the node_modules directory.

Note : In future project development, be sure to add the node_modules folder to the .gitignore ignore file.

3 Quickly create package.json


The npm package management tool provides a shortcut command to quickly create the package management configuration file package.json in the directory where the command is executed :

// 作用:在执行命令所在目录中,快速新建 package.json 文件
npm init -y

// 执行该命令的时机,是在新建好项目文件夹的时候,不要开始写任何代码,第一步要做的任务就是执行该命令,而且这个命令在项目中只需要执行一次就够了,目的就是创建package.json文件。

Notice:

  • The above command can only be successfully run in the English directory ! Therefore, the name of the project folder must be named in English, not in Chinese, and there must be no spaces.

  • When running the npm install command to install a package, the npm package management tool will automatically record the package name and version number in package.json.

4 dependencies node

In the package.json file, there is a dependencies node, which is specially used to record which packages you have installed using the npminstall command.

5 Install all packages at once

When we get a project that excludes node_modules, we need to download all the packages to the project before the project can run.

Otherwise, an error similar to the following will be reported:

// 由于项目运行依赖于moment这个包,如果没有提前安装好这个包,就会报一下错误
Error: Cannot find module 'moment'

You can run npm installthe command (or npmi) to install all dependencies at once :

// 执行 npm install 命令时,npm 包管理工具会先读取 package.json 中的 dependencies 节点。
// 读取到记录的所有依赖包名称和版本号之后,npm 包管理工具会把这些包一次性下载到项目中。
npm install

6 Uninstall the package

You can run npm uninstallthe command to uninstall the specified package:

// 使用 npm uninstall 具体的报名,来卸载包
npm uninstall moment

Note: After the npm uninstall command is successfully executed, the uninstalled package will be automatically removed from the dependencies in package.json.

7 devDependcise node

If some packages are only used in the project development stage and will not be used after the project goes online , it is recommended to record these packages in the devDependencies node.

Correspondingly, if some packages need to be used after development and project launch, it is recommended to record these packages in the dependencies node.

You can log packages into the devDependencies node using the following command:

// 安装指定的包,并记录到 devDependcise 节点中
npm i 报名 -D

// 注意:上述命令是简写形式,等价于下面完整的写法
npm  install 报名 --save-dev

6.4 Solve the problem of slow download speed

1 Why is the download speed slow

When using npm to download the package, it is downloaded from the https://registry.npmjs.org/ server abroad by default. At this time, the transmission of network data needs to go through a long submarine optical cable, so the download speed will be very slow.

Extended reading - submarine cable:

2 Taobao NPM mirror server

Taobao has set up a server in China to synchronize the packages on foreign official servers to domestic servers , and then provide the service of downloading packages in China. Thereby greatly improving the speed of downloading.

extension:

Mirroring is a form of file storage. The data on one disk has an identical copy on another disk .

3 Switch the download mirror source of npm

The image source of the downloaded package refers to 下包的服务器地址.

// 查看当前的下包镜像源
npm config get registry

// 将下包的镜像源切换为淘宝镜像源
npm config set registry=https://registry.npm.taobao.org/

4 nrm

In order to switch the image source of the package more conveniently, we can install the small tool nrm , and use the terminal commands provided by nrm to quickly view and switch the image source of the package.

// 通过 npm 包管理器,将 nrm 安装为全局可用的工具
npm i nrm -g

// 查看所有可用的镜像源
nrm ls

// 将下包的镜像源切换为 taobao 镜像
nrm use taobao

6.5 Classification of packages

Packages downloaded using the npm package management tool are divided into two categories: 项目包, 全局包.

1 item pack

Those packages that are installed into the project's node_modules directory are project packages.

Project packages are divided into two categories, namely:

  • 开发依赖包(Packages recorded in the devDependencies node are only used during development)

  • 核心依赖包(The packages recorded in the dependencies node will be used during development and after the project goes online)

npm i 包名 -D  	// 开发依赖包
npm i 包名		// 核心依赖包

2 global packages

When executing the npm install command, if -gthe parameter , the package will be installed as 全局包.

The global package will be installed to the C:\Users\user directory\AppData\Roaming\npm\node_modules directory.

npm i 包名 -g			// 安装指定的包到全局
npm uninstall 包名 -g	// 指定卸载全局安装的包

Notice:

  • Only tool-like packages need to be installed globally. Because they provide useful terminal commands.

  • To determine whether a package needs to be installed globally before it can be used, you can refer to the official instructions for use .

3 i5ting_toc

i5ting_toc is a small tool that can convert md documents into html pages. The steps are as follows:

// 将 i5ting_toc 安装为全局包
npm install -g i5ting_toc

// 调用 i5ting_toc 轻松实现 md 转 HTML 的功能。-o 表示转换完成后自动在浏览器打开 
i5ting_toc -f 要转换的md文件的路径 -o

6.6 Canonical package structure

After clarifying the concept of a package and how to download and use it, let's take a deeper look at the internal structure of the package .

A standardized package, its composition structure, must meet the following three requirements:

  • ① The package must exist 单独的目录with

  • ② The package management configuration file must be included in the top-level directory of package.jsonthe

  • ③ package.json must contain name,version,mainthese three attributes, representing the package respectively 名字、版本号、包的入口.

Note: The above three requirements are the format that a standardized package structure must comply with. For more constraints, you can refer to the following URL:

https://yarnpkg.com/zh-Hans/docs/package-json

6.7 Publish packages on npm

1 Register npm account

①Visit https://www.npmjs.com/ website, click the sign up button to enter the registration user interface

② Fill in the account-related information: Full Name, Public Email, Username, Password

③Click the Create an Account button to register an account

④Log in to the email, click the verification link to verify the account

2 Log in to the npm account

After the npm account registration is completed, you can execute the npm login command in the terminal, and enter the user name, password, and email address in sequence to log in successfully.

**Note:**Before running the npm login command, you must first switch the server address of the package to the official server of npm. Otherwise, the release package will fail!

3 Publish the package to npm

After switching the terminal to the root directory of the package, run the npm publish command to publish the package to npm (note: the package names cannot be the same).

4 Remove published packages

Run npm unpublish 包名 --forcethe command to remove a published package from npm.

Notice:

①The npm unpublish command can only delete packages published within 72 hours

②Packages deleted by npm unpublish are not allowed to be republished within 24 hours

③Be cautious when publishing packages, try not to publish meaningless packages on npm !


7 Module loading mechanism

7.1 Prioritize loading from cache

模块在第一次加载后会被缓存. This also means that multiple invocations require()will not cause the module's code to be executed multiple times.

Note: Whether it is a built-in module, a user-defined module, or a third-party module, they will be loaded from the cache first, thus 提高模块的加载效率.

7.2 Loading mechanism of built-in modules

Built-in modules are modules officially provided by Node.js, 内置模块的加载优先级最高.

For example, require('fs') always returns the built-in fs module, even if there is a package with the same name in the node_modules directory called fs.

7.3 Loading mechanism of custom modules

When using require() to load a custom module, you must specify a path identifier starting with ./ or .../ .

When loading a custom module, if no path identifier such as ./ or .../ is specified , node will load it as a built-in module or a third-party module .

At the same time, when using require() to import a custom module, if the file extension is omitted ,

Then Node.js will 按顺序try to load the following files respectively:

确切的文件名Load according to

② Complete .jsthe extension to load

③ Complete the .jsonextension to load

④ Complete .nodethe extension to load

⑤Failed to load, the terminal reported an error

7.4 Loading mechanism of third-party modules

If the module identifier passed to require() is not a built-in module, nor does it start with './' or '.../', Node.js starts from the current module's parent directory and tries to load it from the /node_modules folder third-party modules.

If the corresponding third-party module is not found, move to the next parent directory and load it until the root directory of the file system.

For example, assuming require('tools') is called in the 'C:\Users\xiaoxu\project\foo.js' file, Node.js will search in the following order:

① C:\Users\xiaoxu\project\node_modules\tools

② C:\Users\xiaoxu\node_modules\tools

③ C:\Users\node_modules\tools

④ C:\node_modules\tools

7.5 Directories as modules

When passing a directory as a module identifier to require() for loading, there are three loading methods:

①Find a file called package.json in the loaded directory, and look for the main attribute as the entry for require() loading

②If there is no package.json file in the directory, or the main entry does not exist or cannot be parsed, Node.js will try to load the index.js file in the directory.

③If the above two steps fail, Node.js will print an error message on the terminal, reporting the absence of the module: Error: Cannot find module 'xxx'


8 Express

8.1 Introduction to Express

1 What is Express

The concept given by the official: Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架.

Popular understanding: The function of Express is similar to the built-in http module of Node.js, and it is specially used to create a web server.

The essence of Express : it is a third-party package on npm, which provides a convenient way to quickly create a web server.

Express's Chinese official website: http://www.expressjs.com.cn/

2 Further understanding of Express

Thoughts: Can I create a web server without using Express?

Answer: Yes, you can use the native http module provided by Node.js.

Thinking: Both Shengyu and He Shengliang (with the built-in http module, why use Express)?

Answer: The http built-in module is very complicated to use and the development efficiency is low; Express 是基于内置的 http 模块进一步封装出来的,能够极大的提高开发效率.

Thinking: What is the relationship between http built-in modules and Express?

Answer: Similar to the relationship between Web API and jQuery in the browser. The latter is further encapsulated based on the former.

3 What Express can do

For front-end programmers, the two most common servers are:

  • Web 网站服务器: A server dedicated to providing web page resources to the outside world.

  • API 接口服务器: A server that provides an API interface to the outside world.

With Express, we 可以方便、快速的创建 Web 网站的服务器或 API 接口的服务器.

8.2 Basic usage of Express

1 installation

In the directory where the project is located, run the following terminal command to install express into the project:

npm i express@4.17.1

2 Create a basic web server

// 1 导入 express
const express = require('express')

// 2 创建 web 服务器
const app = express()

// 3 启动 web 服务器
app.listen(80,()=>{
    
    
    console.log('express server runing at http://127.0.0.1');
})

3 Listen for GET requests

app.get()method, which can monitor the client's GET request.

Grammar format:

// 参数1:客户端请求的 URL 地址
// 参数2:请求对应的处理函数
// req:请求对象(包含了与请求相关的属性与方法)
// res:响应对象(包含了与响应相关的属性与方法)

app.get('请求URL', (req, res) => {
    
    
    ... 处理函数
})

4 Listen for POST requests

app.post()method, which can monitor the client's POST request.

Grammar format:

// 参数1:客户端请求的 URL 地址
// 参数2:请求对应的处理函数
// req:请求对象(包含了与请求相关的属性与方法)
// res:响应对象(包含了与响应相关的属性与方法)

app.post('请求URL', (req, res) => {
    
    
    ... 处理函数
})

5 Respond to the client with the content

res.send()method, you can send the processed content to the client.

app.get("/user", (req, res) => {
    
    
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 JSON 对象
  res.send({
    
     name: "xiaoxu", age: 20 });
});

app.post("/user", (req, res) => {
    
    
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 文本字符串
  res.send('请求成功');
});

6 Obtain the query parameters carried in the URL

req.queryObject, which can be accessed by the client through 查询字符串the form, parameters sent to the server:

// req.query 默认是一个空对象
// 客户端使用 ?name=zs&age=20 这种查询字符串形式,发送到服务器的参数
// 可以通过 req.query 对象访问
// 例如:req.query.name  req.query.age

app.get("/", (req, res) => {
    
    
  console.log(req.query);
});

7 Get the dynamic parameters in the URL

req.paramsObjects that can be placed in URLs by :matching dynamic parameters.

// req.params 默认是一个空对象
// 里面存放着通过 : 动态匹配到的参数值

app.get('/user/:id', (req, res) => {
    
    
  console.log(req.params); //{ id:1 }
})

// 注意:
// 其中冒号 : 是固定的,id不是固定的,可以是任意的,是匹配完成后参数的名称
// 动态参数可以有多个
app.get('/user/:id/:username', (req, res) => {
    
    
  console.log(req.params); // { id:1, username:'zs' }
})

8.3 Hosting static resources

1 express.static()

express provides a very useful function called express.static().

Through it, we can 非常方便地创建一个静态资源服务器, for example, open access to pictures, CSS files, and JavaScript files in the public directory through the following code:

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

// 调用 app.use 这个函数,在函数中调用 express.static() 这个方法。
// 在这个方法中需要去指定哪个目录作为静态资源文件夹,进行共享向外托管。
// 指定 public 目录,即可访问 public 目录中的所有文件了。

Now, you can access all files in the public directory:

http://localhost:3000/images/bg.jpg

http://localhost:3000/css/style.css

http://localhost:3000/js/login.js

**Note: **Express searches for files in the specified static directory and provides access paths to resources.

Therefore, 存放静态文件的目录名不会出现在 URL 中.

2 Host multiple static resource directories

If you want to host multiple static resource directories, call express.static()the function :

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

When accessing static resource files, express.static() 函数会根据目录的添加顺序查找所需的文件.

3 Mount path prefix

If you want to access the path before the managed static resource, 挂载路径前缀you can use the following method:

app.use('/public', express.static('public'))

Now, you can access files in the public directory by prefixing them with /public:

http://localhost:3000/public/images/kitten.jpg

http://localhost:3000/public/css/style.css

http://localhost:3000/public/js/app.js

8.4 nodemon

1 Why use nodemon

When writing and debugging a Node.js project, if you modify the code of the project, you need to close it manually frequently, and then restart it, which is very cumbersome.

Now, we can use the tool nodemon (https://www.npmjs.com/package/nodemon), which can monitor changes in project files. When the code is modified, nodemon will automatically restart the project for us, which is very convenient development and debugging.

2 install nodemon

npm install -g nodemon

3 use nodemon

When writing a website application based on Node.js, the traditional way is to run the node app.js command to start the project. The disadvantage of this is that after the code is modified, the project needs to be restarted manually.

Now, we can replace the node command with the nodemon command, using nodemon app.jsto start the project. The benefits of doing this are:

代码被修改之后,会被 nodemon 监听到,从而实现自动重启项目的效果

node app.js

nodemon app.js

9 Express Routing

9.1 The concept of routing

1 What is routing

In Express, routing refers to the mapping relationship 客户端的请求with servers 务器处理函数.

2 The 3 components of routing

Routing in Express consists of 3 parts, namely: 请求的类型、请求的 URL 地址、处理函数.

The format is as follows: (the type and address are related to the client)

app.METHOD(PATH, HANDLER)

METHOD	表示请求的类型		method
PATH	表示请求的地址 	path
HANDLER	处理函数		  handler

Routing example in Express:

// 匹配 get 请求,且请求 url 为 / 
app.get('/', function(req, res){
    
    
  res.send("hello world");  
})

// 匹配 post 请求,且请求 url 为 / 
app.post('/', function(req, res){
    
    
  res.send("hello world");  
})

3 Routing matching process

Whenever a request arrives at the server, 需要先经过路由的匹配the corresponding processing function will be called only after the matching is successful.

When matching, the matching will be performed in the order of the routing. If 请求类型the 请求的urlmatching is successful at the same time, Express will transfer the request to the corresponding function for processing.

Points to note for route matching:

  • 先后顺序① Match as defined

  • The corresponding processing function will be called only if the matching of the sum 请求类型and the same time is successful请求的URL

9.2 Use of routing

1 The simplest usage

The easiest way to use routing in Express is to mount the routing on the app.

2 Modular Routing

In order to facilitate the modular management of routes, Express does not recommend that routes be mounted directly on the app , but is recommended 将路由抽离为单独的模块.

The steps to extract routing into a separate module are as follows:

  • ① Create the .js file corresponding to the routing module

  • ② Call express.Router()the function to create a routing object

  • ③ Mount a specific route to the route object

  • ④ Use to share routing objects module.exportsoutward

  • ⑤ Use app.use()the function to register the routing module

3 Create a routing module

(1) Create a basic server

const express = require("express");
const app = express();

app.listen(80, () => {
    
    
  console.log("http://127.0.0.1");
});

(2) Create a routing module

// 1 导入 express
const express = require("express");

// 2 创建路由对象
const router = express.Router();

// 3 挂载具体的路由
router.get("/user/list", (req, res) => {
    
    
  res.send("Get user list.");
});
router.post("/user/add", (req, res) => {
    
    
  res.send("Add new user.");
});

// 4 向外导出路由对象
module.exports = router;

4 Register the routing module

const express = require("express");
const app = express();

// 1 导入路由模块
const router = require("./router");

// 2 使用app.use() 注册路由模块
app.use(router);

app.listen(80, () => {
    
    
  console.log("http://127.0.0.1");
});

Note: app.use()What the function does is: 注册全局中间件.

5 Add a prefix to the routing module

Similar to how to uniformly mount access prefixes for static resources when hosting static resources, the way to add prefixes to routing modules is also very simple:

app.use("api", router);
// 使用 app.use() 注册路由模块,并添加统一的访问前缀 /api

10 Express middleware

10.1 The concept of middleware

1 What is middleware

Middleware (Middleware), specifically refers to business processes中间处理环节 .

2 examples

When treating sewage, there are generally three treatment steps to ensure that the treated wastewater meets the discharge standards.

These three intermediate processing links of sewage treatment can be called middleware. Middleware must have inputs and outputs.

3 Call process of Express middleware

When a request arrives at the Express server, multiple middleware can be called continuously to preprocess the request.

4 Format of Express middleware

Express middleware is essentially a function processing function . The format of Express middleware is as follows:

Note: In the formal parameter list of the middleware function, 必须包含 next 参数. The route processing function only contains
req and res.

5 The role of the next function

The next function is 多个中间件连续调用the key to the realization, it means to transfer the flow relationship 转交to the next one 中间件或路由.

10.2 First experience with Express middleware

1 Define the middleware function

Define the simplest middleware function:

const express = require("express");
const app = express();

// 产量 mw 所指向的,就是一个中间件函数
const mw = function (req, res, next) {
    
    
  console.log("定义一个最简单的中间件函数");
  // 注意:当中间件的业务逻辑处理完毕后,必须调用 next() 函数
  // 表示把流转关系转交给下一个中间件或路由。
  next()
};

app.listen(80, () => {
    
    
  console.log("http://127.0.0.1");
});

2 Global middleware

Initiated by the client 任何请求, after reaching the server, 都会触发的中间件is called 全局生效的中间件.

By calling app.use(中间件函数), you can define a globally effective middleware, the sample code is as follows:

// 产量 mw 所指向的,就是一个中间件函数
const mw = function (req, res, next) {
    
    
  console.log("定义一个最简单的中间件函数");
  // 注意:当中间件的业务逻辑处理完毕后,必须调用 next() 函数
  // 表示把流转关系转交给下一个中间件或路由。
  next()
};

// 将 mw 注册为全局生效的中间件。
app.use(mw)

3 Simplified form of global middleware

The function is passed in app.use.

app.use((req, res, next) => {
    
    
  console.log("定义一个最简单的中间件函数");
  next();
});

4 The role of middleware

Multiple middleware share the same req and res . Based on such features, we can uniformly add custom properties or methods to req or res objects in upstream middleware for downstream middleware or routing to use.

app.use((req, res, next) => {
    
    
	// 获取到请求到达服务器的时间
    const time = Date.now();
    
    // req 对象,挂载自定义属性,从而把时间共享给后面的所有路由
    req.startTime = time

    next();
});

5 Define multiple global middleware

app.use()Multiple global middleware can be defined in succession.

After the client request reaches the server, it will be called in sequence according to the order defined by the middleware. The sample code is as follows:

6 Locally effective middleware

不使用 app.use() 定义的中间件, called 局部生效的中间件.

The sample code is as follows:

const express = require("express"); // 导入 express 模块
const app = express(); // 创建 express 的服务器实例

// 1 定义中间件函数
const mw1 = (req, res, next) => {
    
    
  console.log("调用了局部生效的中间件");
  next();
};

// 2 创建路由
app.get("/", mw1, (req, res) => {
    
    
  // 该请求,会调用 mw1 中间件
  res.send("Home page.");
});
app.get("/user", (req, res) => {
    
    
  // 该请求不会调用 mw1 中间件
  res.send("User page.");
});

app.listen(80, () => {
    
    
  console.log("http://127.0.0.1");
});

7 Define multiple partial middleware

In routing, through the following two 等价ways 使用多个局部中间件:

// 一下两种写法是“完全等价”的,可以选择任意一种方式进行使用 
app.get("/", mw1, mw2, (req, res) => {
    
    
  res.send("Home page.");
});
app.get("/", [mw1, mw2], (req, res) => {
    
    
  res.send("Home page.");
});

8 Understand the 5 precautions for using middleware

  • ① Be sure to 路由之前register the middleware
  • 可以连续调用多个中间件② Process the request sent by the client
  • ③ After executing the business code of the middleware,不要忘记调用 next() 函数
  • ④ In order 防止代码逻辑混乱, do not write additional code after calling the next() function
  • ⑤ When calling multiple middleware continuously,多个中间件之间,共享 req 和 res 对象

10.3 Classification of middleware

Express officially divides common middleware usage into five categories, namely:

  • 应用级别middleware
  • 路由级别middleware
  • 错误级别middleware
  • Express 内置middleware
  • 第三方middleware

1 Application-level middleware

Through app.use() or app.get() or app.post(), 绑定到 app 实例上的中间件it is called application-level middleware. The code example is as follows:

// 应用级别中间件(全局中间件)
app.use((req, res, next) => {
    
    
  next();
});

// 应用级别中间件(局部中间件)
app.get("/", mw1,(req, res) => {
    
    
  res.send("Home page.");
});

2 Routing level middleware

绑定到 express.Router() 实例上The middleware is called routing-level middleware.

Its usage is no different from application-level middleware. However, the application-level middleware is bound to the app instance, and the routing-level middleware is bound to the router instance. The code example is as follows:

const app = express()
const router = express.Router()

// 路由级别中间件
router.use((req, res, next) => {
    
    
    next()
})

app.use('/', router);

3 Error level middleware

**Function:**Specially used to capture abnormal errors that occur throughout the project, thereby 防止项目异常崩溃causing problems.

**Format:** In the function processing function of the error level middleware, there must be 4 个形参, and the order of formal parameters is (err, req, res, next).

// 1 人为的制造错误
app.get('/', function(req, res){
    
    
  throw new Error('服务器内部发生了错误') // 抛出一个自定义的错误
  res.send('Home Page')
})

// 2 定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的崩溃
app.use((err, req, res, next) => {
    
    
  console.log('发生了错误!', err.message) // 在服务器答应错误消息 
  res.send('Error:', err.message) // 向客户响应错误相关的内容
})

**Note:** Error-level middleware must be registered after all routes!

4 Express built-in middleware

Since Express 4.16.0, Express has built-in 3 commonly used middleware, which greatly improves the development efficiency and experience of Express projects:

  • express.staticBuilt-in middleware for fast hosting of static resources, such as: HTML files, pictures, CSS styles, etc. (no compatibility)
  • express.jsonParse request body data in JSON format (with compatibility, only available in version 4.16.0+)
  • express.urlencodedParse request body data in URL-encoded format (with compatibility, only available in version 4.16.0+)
// 配置解析 application/json 格式数据的内置中间件
app.use(express.json());

// 配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
app.use(express.urlencoded({
    
     extended: false}))

5 Third-party middleware

The middleware that is not officially built-in by Express but developed by a third party is called third-party middleware.

In the project, you can download and configure third-party middleware on demand, so as to improve the development efficiency of the project.

For example: In versions prior to [email protected], body-parser, a third-party middleware, is often used to parse request body data. The steps to use are as follows:

  • ① Run npm install body-parser to install middleware
  • ② Use require to import middleware
  • ③ Call app.use() to register and use middleware

**Note: **Express's built-in express.urlencoded middleware is further encapsulated based on the third-party middleware body-parser.

10.4 Custom middleware

https://www.bilibili.com/video/BV1a34y167AZ?p=49&vd_source=79669bc2885938b4485dee3a65450388


11 Using Express to write interface

11.1 Create a basic server

// 导入 express 模块
const express = require("express");

// 创建 express 的服务器实例
const app = express();

// 调用 app.listen 方法,指定端口号并启动 web 服务器
app.listen(80, function () {
    
    
  console.log("Express server running at http://127.0.0.1");
});

11.2 Create an API routing module

apiRouter.js routing module

const express = require('express');

const router = express.Router();

// 在这里挂载路由

module.exports = router;

app.js imports and registers the routing module

const express = require("express");
const app = express();


// 导入路由模块
const router = require("./apiRouter");

// 把路由模块,注册到 app 上
app.use("/api", router);


app.listen(80, function () {
    
    
  console.log("Express server running at http://127.0.0.1");
});

11.3 Write get interface

The client 查询字符串sends data to the server.

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

// 在这里挂载路由
router.get("/get", (req, res) => {
    
    
  // 1 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query;

  // 2 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    
    
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: "GET 请求成功!", // 状态的描述
    data: query, // 需要响应给客户端的具体数据
  });
});

module.exports = router;

11.4 Write post interface

The client passes 请求体传输数据to the server.

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

router.post("/post", (req, res) => {
    
    
  // 1 获取客户端通过请求体,发送到服务器的 URL-encoded 数据
  const body = req.body;

  // 2 调用 res.send() 方法,把数据响应给客户端
  res.send({
    
    
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: "POST 请求成功!", // 状态的描述
    data: body, // 需要响应给客户端的具体数据
  });
});

module.exports = router;

Note: If you want to get the request body data URL-encodedin the format , you must configure the middleware, app.use(express.urlencoded({ extended: false }));.

If this middleware is not configured, the data in the request body cannot be obtained through req.body.

11.5 CORS cross domain resource sharing

1 Cross-domain problem of interface

There is a very serious problem in the GET and POST interfaces written: 不支持跨域请求.

There are two main solutions to solve the interface cross-domain problem:

  • CORS(Mainstream solution, 推荐使用)

  • JSONP(Defective solution: only GET requests are supported)

2 Use cors middleware to solve cross-domain problems

cors is a third-party middleware for Express. By installing and configuring cors middleware, you can easily solve cross-domain problems.

The usage steps are divided into the following 3 steps:

  • ① Run npm install cors安装中间件

  • ② 使用 const cors = require(‘cors’) 导入中间件

  • ③ Call app.use(cors()) before routing配置中间件

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require("cors");
app.use(cors());
// 导入 express 模块
const express = require("express");

// 创建 express 的服务器实例
const app = express();

// 配置解析表单数据的中间件
app.use(express.urlencoded({
    
     extended: false }));

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require("cors");
app.use(cors());

// 导入路由模块
const router = require("./apiRouter");

// 把路由模块,注册到 app 上
app.use("/api", router);

// 调用 app.listen 方法,指定端口号并启动 web 服务器
app.listen(80, function () {
    
    
  console.log("Express server running at http://127.0.0.1");
});

3 What is CORS

CORS (Cross-Origin Resource Sharing) consists of a series of HTTP response headers, which determine whether the browser prevents the front-end JS code from obtaining resources across domains .

The browser's 同源安全策略default will prevent web pages from "cross-domain" access to resources. However, if the interface server is used 配置了 CORS 相关的 HTTP 响应头, the cross-domain access restrictions on the browser side can be lifted.

4 CORS considerations

  • ① CORS is mainly in 服务器端进行配置. The client browser can request the interface with CORS enabled without any additional configuration .

  • ②CORS in the browser 有兼容性. Only browsers that support XMLHttpRequest Level2 can normally access the server interface with CORS enabled (for example: IE10+, Chrome4+, FireFox3.5+).

5 CORS response header - Access-Control-Allow-Origin

An Access-Control-Allow-Origin field can be carried in the response header , and its syntax is as follows:

Access-Control-Allow-Origin: <origin> | *
    
// 冒号前面为响应头的 名称
// 冒号后面是响应头的 值。值可以是一个具体的域名,也可以是一个星号

Among them, the value of the origin parameter specifies the external domain URL that is allowed to access the resource.

For example, the following field values ​​will only allow requests from http://xxx.cn:

res.setHeader('Access-Control-Allow-Origin:', 'http://xxx.cn')
// 表示这个服务器只支持 这个http://xxx.cn网页下所有的跨域请求

If the value of the Access-Control-Allow-Origin field is specified as a wildcard *, it means 允许来自任何域的请求.

res.setHeader('Access-Control-Allow-Origin:', '*')

6 CORS response header - Access-Control-Allow-Headers

By default, CORS only supports the client sending the following to the server 9 个请求头:

Accept, Accept-Language, Content-Language, DPR, Downlink, Save-Data, Viewport-Width, Width, Content-Type (values ​​are limited to text/plain, multipart/form-data, application/x-www-form-urlencoded one of three)

If the client sends additional request header information to the server, it needs to be on the server side, 通过 Access-Control-Allow-Headers 对额外的请求头进行声明otherwise the request will fail this time!

// 允许客户端额外向服务器发送 Content-Type 请求头和 X-Custom-Header 请求头

// 注意:多个请求头之间使用英文的逗号进行分割
res.setHeader('Access-Control-Allow-Headers:', 'Content-Type, X-Custom-Header')

7 CORS response header - Access-Control-Allow-Methods

By default, CORS only supports GET, POST, and HEAD requests initiated by the client.

If the client wants to request resources from the server through PUT, DELETE, etc., it needs to be on the server side, 通过 Access-Control-Alow-Methods来指明实际请求所允许使用的 HTTP 方法.

The sample code is as follows:

// 只允许 POST、GET、DELETE、HEAD 请求方法
res.setHeader('Access-Control-Allow-Methods:', 'POST, GET, DELETE, HEAD')

// 允许所有的  HTTP 请求方法
res.setHeader('Access-Control-Allow-Methods:', '*')

8 Classification of CORS requests

When the client requests the CORS interface, according to 请求方式和请求头the difference, the CORS request can be divided into two categories, namely:

  • ① Simple request

  • ②Pre-check request

9 simple requests

A request that satisfies the following two conditions at the same time is a simple request:

  • ① Request method:GET、POST、HEAD 三者之一

  • ② The following fields of HTTP header information 不超过: no custom header field, Accept, Accept-Language, Content-Language, DPR, Downlink, Save-Data, Viewport-Width, Width, Content-Type (only three values ​​application /x-www-form-urlencoded, multipart/form-data, text/plain)

10 Preflight Request

As long as the request meets any of the following conditions, a preflight request is required:

  • ① The request method is a request method type other than GET, POST, or HEAD

  • ② The request header contains custom header fields

  • ③ Send data in application/json format to the server

Before the browser formally communicates with the server, 浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求so this time the OPTION request is called 预检请求.

服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

11 Difference between simple request and preflight request

Characteristics of simple requests : between client and server 只会发生一次请求.

Features of the preflight request : Between the client and the server 会发生两次请求, the real request will be initiated only after the OPTION preflight request is successful.

11.6 JSONP interface

1 JSONP concept and features

Concept: The browser requests data on the server through the src attribute of <script>the tag , and at the same time, the server returns a function call. This way of requesting data is called JSONP.

Features:

  • ① JSONP is not a real Ajax request because it does not use the XMLHttpRequest object.

  • ② JSONP only supports GET requests, not POST, PUT, DELETE and other requests.

2 Notes on creating JSONP interface

If CORS cross-origin resource sharing has been configured in the project, in order to prevent conflicts , 必须在配置 CORS 中间件之前声明 JSONP 的接口. Otherwise, the JSONP interface will be processed as an interface with CORS enabled.

The sample code is as follows:

// 必须在配置 cors 中间件之前,配置 JSONP 的接口
app.get("api/jsonp", (req, res) => {
    
    
  // 定义jsonp接口的具体实现过程
});

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require("cors");
app.use(cors());

3 Implement the JSONP interface

  • ① Obtain the information sent by the client回调函数的名字

  • ② Obtained in the form of JSONP发送给客户端的数据

  • ③ According to the data obtained in the first two steps,拼接出一个函数调用的字符串

  • ④ Respond to the <script>tag

app.get("api/jsonp", (req, res) => {
    
    
  // 1 获取客户端发送过来的回调函数的名字
  const funcName = req.query.callback;

  // 2 得到要通过 jsonp 形式发送给客户端的数据
  const data = {
    
     naem: "zs", age: 20 };

  // 3 根据前两步得到的数据,拼接出一个函数调用的字符串
  const scriptStr = `${
      
      funcName}(${
      
      JSON.stringify(data)})`;

  // 4 把上一步拼接得到的字符串,响应给客户端的 <script> 标签进行解析执行
  res.send(scriptStr);
});

4 Initiate a JSONP request in the webpage


If you want to request resources from the server through PUT, DELETE, etc., you need to use 通过 Access-Control-Alow-Methods来指明实际请求所允许使用的 HTTP 方法.

The sample code is as follows:

// 只允许 POST、GET、DELETE、HEAD 请求方法
res.setHeader('Access-Control-Allow-Methods:', 'POST, GET, DELETE, HEAD')

// 允许所有的  HTTP 请求方法
res.setHeader('Access-Control-Allow-Methods:', '*')

8 Classification of CORS requests

When the client requests the CORS interface, according to 请求方式和请求头the difference, the CORS request can be divided into two categories, namely:

  • ① Simple request

  • ②Pre-check request

9 simple requests

A request that satisfies the following two conditions at the same time is a simple request:

  • ① Request method:GET、POST、HEAD 三者之一

  • ② The following fields of HTTP header information 不超过: no custom header field, Accept, Accept-Language, Content-Language, DPR, Downlink, Save-Data, Viewport-Width, Width, Content-Type (only three values ​​application /x-www-form-urlencoded, multipart/form-data, text/plain)

10 Preflight Request

As long as the request meets any of the following conditions, a preflight request is required:

  • ① The request method is a request method type other than GET, POST, or HEAD

  • ② The request header contains custom header fields

  • ③ Send data in application/json format to the server

Before the browser formally communicates with the server, 浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求so this time the OPTION request is called 预检请求.

服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

11 Difference between simple request and preflight request

Characteristics of simple requests : between client and server 只会发生一次请求.

Features of the preflight request : Between the client and the server 会发生两次请求, the real request will be initiated only after the OPTION preflight request is successful.

11.6 JSONP interface

1 JSONP concept and features

Concept: The browser requests data on the server through the src attribute of <script>the tag , and at the same time, the server returns a function call. This way of requesting data is called JSONP.

Features:

  • ① JSONP is not a real Ajax request because it does not use the XMLHttpRequest object.

  • ② JSONP only supports GET requests, not POST, PUT, DELETE and other requests.

2 Notes on creating JSONP interface

If CORS cross-origin resource sharing has been configured in the project, in order to prevent conflicts , 必须在配置 CORS 中间件之前声明 JSONP 的接口. Otherwise, the JSONP interface will be processed as an interface with CORS enabled.

The sample code is as follows:

// 必须在配置 cors 中间件之前,配置 JSONP 的接口
app.get("api/jsonp", (req, res) => {
    
    
  // 定义jsonp接口的具体实现过程
});

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require("cors");
app.use(cors());

3 Implement the JSONP interface

  • ① Obtain the information sent by the client回调函数的名字

  • ② Obtained in the form of JSONP发送给客户端的数据

  • ③ According to the data obtained in the first two steps,拼接出一个函数调用的字符串

  • ④ Respond to the <script>tag

app.get("api/jsonp", (req, res) => {
    
    
  // 1 获取客户端发送过来的回调函数的名字
  const funcName = req.query.callback;

  // 2 得到要通过 jsonp 形式发送给客户端的数据
  const data = {
    
     naem: "zs", age: 20 };

  // 3 根据前两步得到的数据,拼接出一个函数调用的字符串
  const scriptStr = `${
      
      funcName}(${
      
      JSON.stringify(data)})`;

  // 4 把上一步拼接得到的字符串,响应给客户端的 <script> 标签进行解析执行
  res.send(scriptStr);
});

Guess you like

Origin blog.csdn.net/qq_53931766/article/details/127511922