Node.js 【Sin terminar】

Nodo.js

Introducción de nodos e instalación del entorno.

Introducción a Node.js

1. ¿Qué es Node.js?

Node.js® es un tiempo de ejecución de JavaScript integrado en el motor JavaScript V8 de Chrome.

Node.js es un entorno de ejecución de JavaScript basado en el motor Chrome V8.

Dirección del sitio web oficial de Node.js: https://nodejs.org/zh-cn/

2. Entorno de ejecución de JavaScript en Node.js

Por favor agregue la descripción de la imagen.

Aviso:

①El navegador es el entorno de ejecución de front-end para JavaScript.

②Node.js es el entorno de ejecución back-end para JavaScript.

③Las API integradas del navegador, como DOM y BOM, no se pueden llamar en Node.js.

3. Qué puede hacer Node.js

Como entorno de ejecución de JavaScript, Node.js solo proporciona funciones y API básicas. Sin embargo, basándose en las capacidades básicas proporcionadas por Node.js, han surgido sin cesar muchas herramientas y marcos poderosos, por lo que aprender Node.js puede hacer que los programadores front-end estén calificados para más trabajos y puestos:

① Basado en el marco Express (http://www.expressjs.com.cn/), las aplicaciones web se pueden crear rápidamente

②Basado en el marco de Electron (https://electronjs.org/), se pueden crear aplicaciones de escritorio multiplataforma

③Basado en el marco restify (http://restify.com/), los proyectos de interfaz API se pueden construir rápidamente

④Leer, escribir y operar bases de datos, crear herramientas prácticas de línea de comandos para ayudar al desarrollo front-end, etc.

JavaScript en la ruta de aprendizaje del navegador:

Sintaxis básica de JavaScript + API integrada del navegador (DOM + BOM) + bibliotecas de terceros (jQuery, art-template, etc.)

Ruta de aprendizaje de Node.js:

Sintaxis básica de JavaScript + módulos API integrados de Node.js (fs, path, http, etc.) + módulos API de terceros (express, mysql, etc.)

Instalación del entorno Node.js

Si desea ejecutar código Javascript a través de Node.js, debe tener un entorno Node.js instalado en su computadora.

El paquete de instalación se puede descargar directamente desde la página de inicio del sitio web oficial de Node.js. Vaya a la página de inicio del sitio web oficial de Node.js (https://nodejs.org/en/), haga clic en el botón verde, descargue la versión requerida y haga doble clic. -haga clic para instalarlo directamente.Can.

1. Distinguir la diferencia entre la versión LTS y la versión actual

①LTS es una versión estable a largo plazo. Para proyectos de nivel empresarial que buscan estabilidad, se recomienda instalar la versión LTS de Node.js.

②La versión actual es una de las primeras en adoptar nuevas funciones. Para los usuarios que estén interesados ​​en probar nuevas funciones, se recomienda instalar la versión actual de Node.js. Sin embargo, puede haber errores ocultos o vulnerabilidades de seguridad en la versión actual, por lo que no se recomienda utilizar la versión actual de Node.js en proyectos de nivel empresarial.

2. Verifique el número de versión de Node.js instalado.

Abra la terminal, ingrese el comando nodo –v en la terminal y presione la tecla Enter para ver el número de versión del Node.js instalado.

Cómo abrir rápidamente la terminal en el sistema Windows:

Use la tecla de acceso directo (tecla del logotipo de Windows + R) para abrir el panel de ejecución, ingrese cmd y presione Enter directamente para abrir la terminal.

3. ¿Qué es una terminal?

Terminal (inglés: Terminal) está especialmente diseñado para desarrolladores como una forma de lograr la interacción persona-computadora.

Como programador calificado, debemos memorizar algunos comandos de terminal de uso común que nos ayudarán a operar y utilizar mejor la computadora.

Ejecutar código JavaScript en un entorno Node.js

①Abra la terminal

②Ingrese la ruta del archivo js que se ejecutará por nodo

1. Teclas de acceso directo en el terminal

En el terminal Windows powershell o cmd, podemos utilizar las siguientes teclas de acceso directo para mejorar la eficiencia operativa del terminal:

①Utilice la tecla ↑ para localizar rápidamente el último comando ejecutado

② Utilice la tecla tab para completar rápidamente la ruta

③Utilice la tecla esc para borrar rápidamente los comandos ingresados ​​actualmente

④Ingrese el comando cls para borrar la terminal

módulo nodo-fs

1. ¿Qué es el módulo del sistema de archivos fs?

El módulo fs es un módulo proporcionado oficialmente por Node.js para archivos operativos. Proporciona una serie de métodos y propiedades para satisfacer las necesidades de operación de archivos de los usuarios.

Por ejemplo:

  • Método fs.readFile(), utilizado para leer el contenido del archivo especificado
  • Método fs.writeFile(), utilizado para escribir contenido en el archivo especificado

Si desea utilizar el módulo fs para operar archivos en código JavaScript, primero debe importarlo de la siguiente manera:

const fs = require('fs')

2. Lea el contenido del archivo especificado.

1. Formato de sintaxis de fs.readFile()

Usando el método fs.readFile(), puede leer el contenido del archivo especificado. El formato de sintaxis es el siguiente:

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

Interpretación de parámetros:

  • Parámetro 1 ruta: parámetro requerido, cadena, que indica la ruta del archivo.
  • Parámetro 2 opciones: Parámetro opcional, que indica el formato de codificación para leer el archivo.
  • Devolución de llamada del parámetro 3: parámetro requerido Una vez completada la lectura del archivo, el resultado de la lectura se obtiene a través de la función de devolución de llamada.

2. Código de muestra de fs.readFile()

Lea el contenido del archivo especificado en formato de codificación utf8 e imprima los valores de err y dataStr:

// 导入fs模块,来操作文件
const fs = require('fs')

// 调用fs.readfile()读取文件
// 参数1:读取文件的存储路径
// 参数2options:可选参数,表示以什么编码格式来读取文件。
// 参数3callback:必选参数,文件读取完成后,通过回调函数拿到读取的结果。
fs.readFile('./files/1.txt', 'utf8', function(err, dataStr) {
    
    
    // 如果读取成功err为null
    // 如果读取失败,则err的值为错误对象,dataStr的值为undefined
    console.log(err)
    console.log('----------')
        // 打印成功的结果
    console.log(dataStr)

})

err: es el resultado después de una lectura fallida

dataStr: el resultado después de una lectura exitosa

3. Determine si el archivo se leyó correctamente.

Puede determinar si el objeto err es nulo para conocer el resultado de la lectura del archivo:

const fs = require('fs')

fs.readFile("./files/1.txt", 'utf8', function(err, result) {
    
    
    if (err) {
    
    
        return console.log('文件读取失败! ' + err.message)
    }
    console.log("文件读取成功,内容是:" + result)
})

3. Escriba contenido en el archivo especificado.

1. Formato de sintaxis de fs.writeFile()

Usando el método fs.writeFile(), puede escribir contenido en el archivo especificado. La sintaxis es la siguiente:

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

Interpretación de parámetros:

  • Parámetro 1: parámetro obligatorio, debe especificar una cadena de ruta del archivo, que indica la ruta de almacenamiento del archivo.
  • Parámetro 2: Parámetro requerido, que indica el contenido a escribir.
  • Parámetro 3: Parámetro opcional, indica el formato en el que escribir el contenido del archivo, el valor por defecto es utf8.
  • Parámetro 4: parámetro requerido, función de devolución de llamada después de que se completa la escritura del archivo.

2. Código de muestra de fs.writeFile()

Escriba el contenido del archivo en la ruta del archivo especificada:

// 导入fs文件系统模块
const fs = require('fs')

// 2.调用fs.wirteFie()方法,写入文件的内容
// - 参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径。
// - 参数2:必选参数,表示要写入的内容。
// - 参数3:可选参数,表示以什么格式写入文件内容,默认值是 utf8。
// - 参数4:必选参数,文件写入完成后的回调函数。
fs.writeFile('./files/2.txt', '嗨嗨嗨', function(err) {
    
    
    // 如果文件写入成功,则err打印出来为null
    // 如果文件写入失败,则err为一个错误对象
    console.log(err)
})

3. Determine si el archivo se escribió correctamente.

Puede determinar si el objeto err es nulo para conocer el resultado de la escritura del archivo:

// 导入fs文件系统模块
const fs = require('fs')

// 2.调用fs.wirteFie()方法,写入文件的内容
// - 参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径。
// - 参数2:必选参数,表示要写入的内容。
// - 参数3:可选参数,表示以什么格式写入文件内容,默认值是 utf8。
// - 参数4:必选参数,文件写入完成后的回调函数。
fs.writeFile('./files/2.txt', 'ajdkdka', function(err) {
    // 如果文件写入成功,则err打印出来为null
    // 如果文件写入失败,则err为一个错误对象
    if (err) {
        return console.log('文件写入失败' + err.message)
    }
    console.log('文件写入成功')
})

4. Problema de empalme dinámico de ruta del módulo fs

Cuando se utiliza el módulo fs para operar archivos, si la ruta de operación proporcionada es una ruta relativa que comienza con ./ o.../, es fácil causar errores de empalme de rutas dinámicas.

Motivo: cuando se ejecuta el código, la ruta completa del archivo operado se unirá dinámicamente desde el directorio donde se ejecuta el comando del nodo.

Solución: cuando utilice el módulo fs para operar archivos, proporcione la ruta completa directamente y no proporcione rutas relativas que comiencen con ./ o.../ para evitar problemas de empalme de rutas dinámicas.

fs.readFile(__dirname + '/files/1.txt', 'utf8', function(err, dataStr) para resolver el empalme dinámico

Por favor agregue la descripción de la imagen.

const fs = require('fs')
    // 出现路径拼接错误的问题,是因为提供了./或../开头的相对路径
    // 如果要解决这个问题,可以直接提供一个完整的文件存放路径就行

// fs.readFile('./files/1.txt', 'utf8', function(err, dataStr) {
//     if (err) {
//         return console.log('文件读取失败' + err.message)
//     }
//     console.log('读取文件成功' + dataStr)
// })

// 移植性非常差,不利于维护
// fs.readFile('D:\\note\\笔记\\javaweb\\node\\files\\1.txt', 'utf8', function(err, dataStr) {
//     if (err) {
//         return console.log('文件读取失败' + err.message)
//     }
//     console.log('读取文件成功' + dataStr)
// })

console.log(__dirname)


fs.readFile(__dirname + '/files/1.txt', 'utf8', function(err, dataStr) {
    if (err) {
        return console.log('文件读取失败' + err.message)
    }
    console.log('读取文件成功' + dataStr)
})
cd ../
 node ./node/05-演示路径问题.js

módulo de ruta de nodo

1. ¿Qué es el módulo de ruta de acceso?

El módulo de ruta es un módulo proporcionado oficialmente por Node.js para procesar rutas. Proporciona una serie de métodos y atributos para satisfacer las necesidades de los usuarios en cuanto al procesamiento de rutas.

Por ejemplo:

  • Método path.join(), utilizado para unir múltiples fragmentos de ruta en una cadena de ruta completa
  • Método path.basename(), utilizado para analizar el nombre del archivo a partir de la cadena de ruta

Si desea utilizar el módulo de ruta para procesar rutas en código JavaScript, primero debe importarlo de la siguiente manera:

const path = require('path')

2. Empalme de caminos

1. Formato de sintaxis de path.join()

Usando el método path.join (), se pueden unir múltiples fragmentos de ruta en una cadena de ruta completa. El formato de sintaxis es el siguiente:

path.join([...paths])

Interpretación de parámetros:

  • …rutas <cadena> Secuencia de fragmentos de ruta
  • Valor de retorno: <cadena>

2. Ejemplo de código de path.join()

Usando el método path.join(), se pueden unir múltiples fragmentos de ruta en una cadena de ruta completa:

…/desplazar ruta anterior

const path = require('path')
const fd = require('fs')
    // const pathStr = path.join('/a', '/b/c', '../', '/d', 'e')
    //     // \a\b\d\e
    // console.log(pathStr)
const pathStr1 = path.join('/a', '/b/c', '../../', '/d', 'e')
console.log(pathStr1)
    // \a\d\e


fd.readFile(path.join(__dirname, './files/1.txt'), 'utf8', function(err, dataStr) {
    if (err) {
        return console.log(err.message)
    }
    console.log(dataStr)
})

Nota: En el futuro, todas las operaciones que impliquen empalme de rutas deben procesarse utilizando el método path.join(). No utilice + directamente para concatenar cadenas.

3. Obtenga el nombre del archivo en la ruta.

1. Formato de sintaxis de ruta.basename()

Usando el método path.basename(), puede obtener la última parte de la ruta. Este método se usa a menudo para obtener el nombre del archivo en la ruta. El formato de sintaxis es el siguiente:

path.basename(path[,ext])

Interpretación de parámetros:

  • ruta <cadena> parámetro requerido, una cadena que representa una ruta
  • ext <cadena> parámetro opcional, que indica la extensión del archivo
  • Devuelve: <cadena> representa la última parte de la ruta

2. Ejemplo de código de ruta.basename()

Usando el método path.basename(), puede obtener la parte del nombre de un archivo a partir de una ruta de archivo:

const path = require('path')
const fpath = '/a/b/c/index.html'


// var fullName = path.basename(fpath)
// console.log(fullName)

var nameWithooutExt = path.basename(fpath, '.html')
console.log(nameWithooutExt)

4. Obtenga la extensión del archivo en la ruta.

1. Formato de sintaxis de ruta.extname()

Usando el método path.extname(), puede obtener la parte de extensión de la ruta. El formato de sintaxis es el siguiente:

path.extname(path)

Interpretación de parámetros:

  • ruta <cadena>Parámetro requerido, una cadena que representa una ruta
  • Retorno: <cadena> Devuelve la cadena de extensión obtenida

2. Ejemplo de código de ruta.extname()

Usando el método path.extname(), puedes obtener la parte de extensión de la ruta:

const path = require('path')
const fpath = '/a/b/c/index.html'

const fext = path.extname(fpath)
console.log(fext)

5. Caja del reloj

módulo nodo-http

1. ¿Qué es el módulo http?

El módulo http es un módulo proporcionado oficialmente por Node.js para crear servidores web. A través del método http.createServer() proporcionado por el módulo http, puede convertir fácilmente una computadora común en un servidor web, proporcionando así servicios de recursos web externos.

Si desea utilizar el módulo http para crear un servidor web, primero debe importarlo:

const http = require('http')

2. Comprenda mejor la función del módulo http

La diferencia entre un servidor y una computadora normal es que el software del servidor web está instalado en el servidor, como IIS, Apache, etc. Al instalar este software de servidor, puede convertir una computadora normal en un servidor web.

En Node.js, no necesitamos utilizar software de servidor web de terceros como IIS y Apache. Porque podemos escribir fácilmente un software de servidor basado en el módulo http proporcionado por Node.js con unas pocas líneas de código simple para proporcionar servicios web externos.

Conceptos relacionados con el servidor

1. dirección IP

La dirección IP es la dirección única de cada computadora en Internet, por lo que la dirección IP es única. Si se compara una "computadora personal" con un "teléfono", entonces una "dirección IP" equivale a un "número de teléfono". Sólo conociendo la dirección IP de la otra parte se puede realizar la comunicación de datos con la computadora correspondiente.

El formato de la dirección IP: generalmente expresado en formato "decimal con punto" (abcd), donde a, b, cyd son todos números enteros decimales entre 0 y 255. Por ejemplo: dirección IP expresada en decimal con puntos (192.168.1.1)

Aviso:

  1. Cada servidor web en Internet tiene su propia dirección IP. Por ejemplo, puede ejecutar el comando ping www.baidu.com en una terminal de Windows para ver la dirección IP del servidor Baidu.
  2. Durante el desarrollo, su computadora es tanto un servidor como un cliente. Para facilitar las pruebas, puede ingresar la dirección IP 127.0.0.1 en su navegador para acceder a su computadora como servidor.

2. Nombre de dominio y servidor de nombres de dominio

Aunque la dirección IP puede marcar de forma única una computadora en la red, la dirección IP es una larga cadena de números, que no es intuitiva y difícil de recordar, por lo que la gente inventó otro esquema de dirección basado en caracteres, el llamado nombre de dominio (Dominio). Nombre). )Dirección.

Existe una correspondencia uno a uno entre las direcciones IP y los nombres de dominio. Esta correspondencia se almacena en una computadora llamada servidor de nombres de dominio (DNS). Los usuarios solo necesitan acceder al servidor correspondiente a través de un nombre de dominio memorable, y el servidor de nombres de dominio implementa el trabajo de conversión correspondiente. Por tanto, un servidor de nombres de dominio es un servidor que proporciona servicios de traducción entre direcciones IP y nombres de dominio.

Aviso:

  1. Las computadoras en Internet pueden funcionar normalmente simplemente usando direcciones IP. Pero con la bendición de los nombres de dominio, el mundo de Internet puede volverse más conveniente.
  2. Durante el desarrollo y las pruebas, el nombre de dominio correspondiente a 127.0.0.1 es localhost, todos representan nuestra propia computadora y no hay diferencia en los efectos de uso.

3. Número de puerto

El número de puerto en la computadora es igual que el número de casa en la vida real. A través del número de la casa, el chico de la comida para llevar puede entregarle con precisión la comida para llevar en numerosas habitaciones del edificio.

Del mismo modo, se pueden ejecutar cientos o miles de servicios web en una sola computadora. Cada servicio web corresponde a un número de puerto único. La solicitud de red enviada por el cliente se puede entregar con precisión al servicio web correspondiente para su procesamiento a través del número de puerto.

Por favor agregue la descripción de la imagen.

Aviso:

  1. Cada número de puerto no puede ser ocupado por múltiples servicios web al mismo tiempo.
  2. En aplicaciones prácticas, se puede omitir el puerto 80 en la URL.

Crea el servidor web más básico

1. Pasos básicos para crear un servidor web

①Importar módulo http

②Crear una instancia de servidor web

③Vincular el evento de solicitud a la instancia del servidor y monitorear la solicitud del cliente

④Iniciar el servidor

2. Crea pasos

Paso 1: importar el módulo http

Si desea crear un servidor web en su propia computadora para proporcionar servicios web al mundo exterior, debe importar el módulo http:

const http = require('http')

Paso 2: crear una instancia de servidor web

Llame al método http.createServer() para crear rápidamente una instancia de servidor web:

const server = http.createServer()

Paso 3: vincular el evento de solicitud a la instancia del servidor

Vincule el evento de solicitud a la instancia del servidor para monitorear las solicitudes de red enviadas por el cliente:

// 使用服务器实例的.on()方法,为服务器绑定一个request事件
server.on('request', (req, res) => {
    
    
    // 只要有客户端请求我们自己的的服务器,就会触发request 事件,从而调用这个事件处理函数
    console.log('Someone visit our web server.')
    
})

Paso 4: inicie el servidor

Llame al método .listen() de la instancia del servidor para iniciar la instancia del servidor web actual:

server.listen(80, function() {
    console.log('server running at http://127.0.0.1');
})
// 1. 导入 http 模块
const http = require('http')

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

// 步骤3 - 为服务器实例绑定 request 事件
// 使用服务器实例的.on()方法,为服务器绑定一个request事件
server.on('request', (req, res) => {
    // 只要有客户端请求我们自己的的服务器,就会触发request 事件,从而调用这个事件处理函数
    console.log('Someone visit our web server.')

})

// 步骤4 - 启动服务器
server.listen(80, function() {
    console.log('server running at http://127.0.0.1:80')
})

3. solicitar objeto de solicitud

Siempre que el servidor reciba la solicitud del cliente, llamará al controlador de eventos de solicitud vinculado al servidor a través de server.on ().

Si desea acceder a datos o propiedades relacionados con el cliente en la función de manejo de eventos, puede utilizar el siguiente método:

const http = require('http')
const server = http.createServer()
    // req是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req) => {
    
    
    // req. url是客户端请求的URL地址
    const url = req.url
        // req. url是客户端请求的URL地址
    const method = req.method
    const str = `Your request url is ${
      
      url},and request method is ${
      
      method} `
    console.log(str)

})
server.listen(80, () => {
    
    
    console.log('server running at http://127.0.0.1')
})

4. objeto de respuesta res

En la función de manejo de eventos de solicitud del servidor, si desea acceder a datos o propiedades relacionados con el servidor, puede utilizar el siguiente método:

const http = require('http')
const server = http.createServer()
    // req是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res) => {
    
    
    // req. url是客户端请求的URL地址
    const url = req.url
        // req. url是客户端请求的URL地址
    const method = req.method
    const str = `Your request url is ${
      
      url},and request method is ${
      
      method} `
    console.log(str)
        // 调用res.en()方法,向客户端响应一些内容
    res.end(str)
})
server.listen(80, () => {
    
    
    console.log('server running at http://127.0.0.1')
})

5. Resuelva el problema de los caracteres chinos confusos.

Cuando se llama al método res.end () para enviar contenido chino al cliente, aparecerán caracteres confusos. En este momento, debe configurar manualmente el formato de codificación del contenido:

const http = require('http')
const server = http.createServer()


server.on('request', (req, res) => {
    
    
    // 定义一个字符串,包含中文一个内容
    const str = `你请求的url地址是${
      
      req.url},请求的method类型为${
      
      req.method}`
        // 调用res.setHeader()方法,设置Content-Type响应头,解决中文乱码问题
    res.setHeader('Content-Type', 'text/html;charset=utf-8')
        // res.end()将内容响应给客户端
    res.end(str)

})


server.listen(80, function() {
    
    
    console.log('server running at http://127.0.0.1')
})

Responder a diferentes contenidos html según diferentes URL

1. Pasos básicos de implementación

①Obtenga la dirección URL solicitada

② Establezca el contenido de respuesta predeterminado en 404 No encontrado

③ Determine si la solicitud del usuario es / o /index.html página de inicio

④ Determinar si el usuario solicitó /about.html Acerca de la página

⑤Establezca el encabezado de respuesta de tipo de contenido para evitar caracteres chinos confusos

⑥Utilice res.end() para responder al cliente con el contenido

2. Contenido de respuesta dinámica

const http = require('http')

const server = http.createServer()

server.on('request', (req, res) => {
    // 请求url地址
    const url = req.url
        // 设置默认的响应内容为404 Not Found
    let Content = '<h1>404 Not Found</h1>'
        // 判断用户请求的是否为 / 或 /index.html 首页
    if (url === '/' || url === '/index.html') {
        Content = '<h1>首页 </h1>'
    } else if (url === '/about.html') {
        Content = '<h1>关于页面</h1>'
    }
    // 判断用户请求的是否为 /about.html 关于页面

    // 设置 Content-Type 响应头,防止中文乱码
    res.setHeader('Content-Type', 'text/html;charset=utf-8')
        // 使用 res.end() 把内容响应给客户端
    res.end(Content)
})


server.listen(80, () => {
    console.log('server running at http://127.0.0.1')
})

Caso: servidor web que implementa el reloj.

nodo-modular

Conceptos básicos de modularidad.

1.1 ¿Qué es la modularidad?

La modularización se refiere al proceso de dividir el sistema en varios módulos capa por capa de arriba a abajo al resolver un problema complejo. Para todo el sistema, los módulos son unidades que se pueden combinar, descomponer y reemplazar.

Modularidad en la programación.

La modularización en el campo de la programación consiste en seguir reglas fijas y dividir un archivo grande en múltiples módulos pequeños que son independientes e interdependientes.

Los beneficios de dividir el código en módulos:

① Reutilización de código mejorada

②Mejorar la mantenibilidad del código.

③Se puede lograr la carga bajo demanda

1.2 Especificaciones modulares

Las especificaciones de modularidad son las reglas que se deben seguir al dividir y combinar código en módulos.

Por ejemplo:

  • ¿Qué formato de sintaxis se utiliza para hacer referencia a los módulos?
  • ¿Qué formato de sintaxis se utiliza en el módulo para exponer a los miembros al mundo exterior?

Los beneficios de las especificaciones modulares: todos cumplen con las mismas especificaciones modulares para escribir código, lo que reduce el costo de la comunicación, facilita enormemente las llamadas mutuas entre varios módulos y beneficia a los demás y a uno mismo.

Modularidad en Node.js

2.1 Clasificación de módulos en Node.js

En Node.js, los módulos se dividen en tres categorías según sus diferentes fuentes, a saber:

  • Módulos integrados (los módulos integrados los proporciona oficialmente Node.js, como fs, path, http, etc.)
  • Módulo personalizado (cada archivo .js creado por el usuario es un módulo personalizado)
  • Módulos de terceros (los módulos desarrollados por terceros no son módulos integrados proporcionados oficialmente, ni son módulos personalizados creados por los usuarios y deben descargarse antes de su uso)

2.2 Cargando módulos

Con el potente método require(), puede cargar los módulos integrados, los módulos definidos por el usuario y los módulos de terceros necesarios para su uso. Por ejemplo:

//加载内置模块
const http = require('http')

//加载用户自定义的模块
const custom = require('./custom.js')

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

Nota: Cuando se utiliza el método require() para cargar otros módulos, se ejecutará el código del módulo cargado.

// 当前这个文件,就是一个自定义模块
console.log('加载了14这个用户自定义模块');



// 注意:在使用require加载用户自定义模块期间,
// 可以省峰.js 的后缀名

const m1 = require('./13-m1.js')

console.log(m1)


2.3 Alcance del módulo en Node.js

1. ¿Cuál es el alcance del módulo?

De manera similar al alcance de la función, solo se puede acceder a las variables, métodos y otros miembros definidos en un módulo personalizado dentro del módulo actual. Esta restricción de acceso a nivel de módulo se llama alcance del módulo.

2. Beneficios del alcance del módulo

Previene el problema de la contaminación variable global.

const username = '张三'


function sayHello() {
    console.log('大家好,我是' + username)
}



const custom = require('./15-模块作用域')
//在另一个js文件里面不会生效

2.4 Compartir miembros en el alcance del módulo hacia afuera

1. objeto del módulo

Hay un objeto de módulo en cada módulo personalizado .js, que almacena información relacionada con el módulo actual y se imprime de la siguiente manera:

Por favor agregue la descripción de la imagen.

2. objeto module.exports

En un módulo personalizado, puede utilizar el objeto module.exports para compartir miembros dentro del módulo para uso externo.

Cuando el mundo exterior usa el método require() para importar un módulo personalizado, lo que obtiene es el objeto al que apunta module.exports.

// 向module.exports对象上挂载username属性
module.exports.username = 'zs'

module.exports.sayHello = function() {
    
    
    console.log(hello)
}
3. Puntos a tener en cuenta al compartir miembros

Cuando se utiliza el método require() para importar un módulo, el resultado de la importación siempre se basará en el objeto señalado por module.exports.

Por favor agregue la descripción de la imagen.

4. objeto de exportación

Dado que la palabra module.exports es complicada de escribir, para simplificar el código para compartir miembros externamente, Node proporciona el objeto exports. De forma predeterminada, las exportaciones y module.exports apuntan al mismo objeto. El resultado final compartido todavía se basa en el objeto señalado por module.exports.

Por favor agregue la descripción de la imagen.

console.log(exports)     /

console.log(module.exports)    //{}

console.log(exports === module.exports)    //true
5. Malentendidos en el uso de exportaciones y module.exports

Recuerde siempre que cuando requiera() un módulo, siempre obtendrá el objeto al que apunta module.exports:

Por favor agregue la descripción de la imagen.

Nota: Para evitar confusiones, se recomienda no utilizar exportaciones y module.exports al mismo tiempo en el mismo módulo.

2.5 Especificaciones de modularidad en Node.js

Node.js sigue la especificación modular CommonJS, que especifica las características de los módulos y cómo los módulos dependen unos de otros.

CommonJS afirma:

①Dentro de cada módulo, la variable del módulo representa el módulo actual.

②La variable del módulo es un objeto y su atributo de exportación (es decir, module.exports) es la interfaz externa.

③Cargar un módulo en realidad carga el atributo module.exports del módulo. El método require() se utiliza para cargar módulos.

npm y paquetes

3.1 Paquete

1. ¿Qué es un paquete?

Los módulos de terceros en Node.js también se denominan paquetes.

Así como computadoras y ordenadores hacen referencia a lo mismo, los módulos y paquetes de terceros hacen referencia al mismo concepto, pero con nombres diferentes.

2. Fuente del paquete

A diferencia de los módulos integrados y los módulos personalizados de Node.js, los paquetes son desarrollados por personas o equipos de terceros y su uso es gratuito para todos.

Nota: Todos los paquetes de Node.js son gratuitos y de código abierto y se pueden descargar y utilizar de forma gratuita sin pagar.

3. ¿Por qué necesitas un paquete?

Dado que los módulos integrados de Node.js solo proporcionan algunas API de bajo nivel, la eficiencia del desarrollo de proyectos basados ​​en módulos integrados es muy baja.

El paquete está encapsulado en función de módulos integrados, lo que proporciona una API más avanzada y conveniente, lo que mejora enormemente la eficiencia del desarrollo.

La relación entre paquetes y módulos integrados es similar a la relación entre jQuery y la API integrada del navegador.

4. ¿Dónde descargar el paquete?

Hay una empresa de TI en el extranjero llamada npm, Inc. Esta empresa tiene un sitio web muy famoso: https://www.npmjs.com/, que es la plataforma para compartir paquetes más grande del mundo. Puede buscarlo en este sitio web. Cualquier bolsa que necesite ¡Siempre y cuando tengas suficiente paciencia!

Hasta ahora, más de 11 millones de desarrolladores en todo el mundo han desarrollado y compartido más de 1,2 millones de paquetes para nuestro uso a través de esta plataforma para compartir paquetes.

npm, Inc. proporciona un servidor en https://registry.npmjs.org/ para compartir todos los paquetes externamente. Podemos descargar los paquetes que necesitamos desde este servidor.

Aviso:

  • Busque el paquete que necesita en el sitio web https://www.npmjs.com/
  • Descargue los paquetes que necesita del servidor https://registry.npmjs.org/
5. Cómo descargar el paquete

npm, Inc. proporciona una herramienta de administración de paquetes. Podemos usar esta herramienta de administración de paquetes para descargar los paquetes requeridos desde el servidor https://registry.npmjs.org/ para uso local.

El nombre de esta herramienta de administración de paquetes es Node Package Manager (conocida como herramienta de administración de paquetes npm) Esta herramienta de administración de paquetes se instala en la computadora del usuario junto con el paquete de instalación de Node.js.

Puede ejecutar el comando npm -v en la terminal para verificar el número de versión de la herramienta de administración de paquetes npm instalada en su computadora.

Primera experiencia de 3,2 npm

1. La forma tradicional de formatear el tiempo.

Por favor agregue la descripción de la imagen.

①Cree un módulo personalizado para formatear la hora

②Cómo definir el tiempo de formato

③Crear función de relleno con ceros

④Exportar la función de tiempo de formato desde el módulo personalizado

⑤Importar módulos personalizados para formatear el tiempo

⑥Llame a la función para formatear la hora.

function dateFormat(dtStr) {
    
    
    const dt = new Date(dtStr)

    const y = dt.getFullYear()
    const m = padZero(dt.getMonth() + 1)
    const d = padZero(dt.getDate())

    const hh = padZero(dt.getHours())
    const mm = padZero(dt.getMinutes())
    const ss = padZero(dt.getSeconds())

    return `${
      
      y}-${
      
      m}-${
      
      d} ${
      
      hh}:${
      
      mm}:${
      
      ss}`

}
// 补零函数
function padZero(n) {
    
    
    return n > 9 ? n : '0' + n
}


module.exports = {
    
    
    dateFormat
}
// 导入自定义的格式化时间的模块
const TIME = require('./19-dateFormat')

// 调用方法,进行时间的格式化
const dt = new Date()

console.log(dt)

const newDT = TIME.dateFormat(dt)
console.log(newDT)
2. Métodos avanzados para formatear la hora.

①Utilice la herramienta de administración de paquetes npm para instalar el momento del paquete de tiempo formateado en el proyecto

②Utilice require() para importar el paquete de tiempo formateado

③Consulte el documento API oficial del momento para formatear la hora.

const moment = require('moment')

const dt = moment().format('YYYY-MM-DD HH:mm:ss')

console.log(dt)
3. Comandos para instalar paquetes en el proyecto

Si desea instalar un paquete con un nombre específico en su proyecto, debe ejecutar el siguiente comando:

npm install 包完整的名称

El comando de empaquetado anterior se puede abreviar al siguiente formato:

npm i 包完整的名称
4. ¿Qué archivos adicionales se incluyen después del embalaje inicial?

Una vez completado el empaquetado inicial, habrá una carpeta adicional llamada node_modules y un archivo de configuración package-lock.json en la carpeta del proyecto.

en:

La carpeta node_modules se utiliza para almacenar todos los paquetes que se han instalado en el proyecto. Cuando require() importa un paquete de terceros, busca y carga el paquete desde este directorio.

El archivo de configuración package-lock.json se utiliza para registrar la información de descarga de cada paquete en el directorio node_modules, como el nombre del paquete, el número de versión, la dirección de descarga, etc.

Nota: Los programadores no deben modificar manualmente ningún código en los archivos node_modules o package-lock.json; la herramienta de administración de paquetes npm los mantendrá automáticamente.

5. Instale la versión especificada del paquete.

De forma predeterminada, cuando utiliza el comando npm install para instalar un paquete, la última versión del paquete se instalará automáticamente. Si necesita instalar una versión específica de un paquete, puede especificar la versión específica mediante el símbolo @ después del nombre del paquete, por ejemplo:

npm i moment@2.22.2
6. Especificación de la versión semántica de los paquetes.

El número de versión del paquete se define en formato "decimal con puntos", con un total de tres dígitos, como 2.24.0

El significado de cada dígito es el siguiente:

1er dígito: versión grande

2do dígito: versión funcional

3er dígito: versión de corrección de errores

Reglas para la promoción del número de versión: siempre que aumente el número de versión anterior, el número de versión posterior volverá a cero.

3.3 Archivo de configuración de gestión de paquetes

npm estipula que se debe proporcionar un archivo de configuración de administración de paquetes llamado package.json en el directorio raíz del proyecto. Se utiliza para registrar cierta información de configuración relacionada con el proyecto. Por ejemplo:

  • Nombre del proyecto, número de versión, descripción, etc.
  • ¿Qué paquetes se utilizan en el proyecto?
  • Qué paquetes solo se utilizan durante el desarrollo
  • Esos paquetes son necesarios durante el desarrollo y la implementación.
1. Problemas con la colaboración entre varias personas

Por favor agregue la descripción de la imagen.

El volumen de todo el proyecto es de 30,4 millones.

El tamaño del paquete de terceros es 28,8M

El tamaño del código fuente del proyecto es 1,6M.

Problemas encontrados: el tamaño del paquete de terceros es demasiado grande, lo que dificulta que los miembros del equipo compartan el código fuente del proyecto.

Solución: eliminar node_modules al compartir

2. Cómo registrar qué paquetes están instalados en el proyecto

En el directorio raíz del proyecto, cree un archivo de configuración llamado package.json, que se puede usar para registrar qué paquetes están instalados en el proyecto. Esto facilita compartir el código fuente del proyecto entre los miembros del equipo después de eliminar el directorio node_modules.

Nota: En el desarrollo futuro del proyecto, asegúrese de agregar la carpeta node_modules al archivo de ignorar .gitignore.

3. Cree rápidamente package.json

La herramienta de administración de paquetes npm proporciona un comando de acceso directo para crear rápidamente el archivo de configuración de administración de paquetes package.json en el directorio donde se ejecuta el comando:

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

Aviso:

  • ¡El comando anterior solo se puede ejecutar con éxito en el directorio en inglés! Por lo tanto, el nombre de la carpeta del proyecto debe estar en inglés, no en chino, y no debe haber espacios.

  • Cuando ejecuta el comando npm install para instalar un paquete, la herramienta de administración de paquetes npm registrará automáticamente el nombre y el número de versión del paquete en package.json.

4. Agregue una descripción de imagen al nodo de dependencias y cárguela directamente.

Por favor agregue la descripción de la imagen.

En el archivo package.json, hay un nodo de dependencias, que se usa especialmente para registrar qué paquetes ha instalado usando el comando npm install.

5. Instale todos los paquetes a la vez.

Cuando eliminamos un proyecto con node_modules, necesitamos descargar todos los paquetes en el proyecto antes de poder ejecutarlo.

De lo contrario, se informará un error similar al siguiente:

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

Puede ejecutar el comando npm install (o npm i) para instalar todos los paquetes dependientes a la vez:

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

npm install
6. Desinstale el paquete

Puede ejecutar el comando npm uninstall para desinstalar el paquete especificado:

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

Nota: Después de que el comando npm uninstall se ejecute correctamente, el paquete desinstalado se eliminará automáticamente de las dependencias de package.json.

7. nodo devDependencies

Si algunos paquetes solo se utilizarán durante la fase de desarrollo del proyecto y no se utilizarán después de que el proyecto esté en línea, se recomienda registrar estos paquetes en el nodo devDependencies.

En consecuencia, si es necesario utilizar algunos paquetes después del desarrollo y el lanzamiento del proyecto, se recomienda registrar estos paquetes en el nodo de dependencias.

Puede utilizar el siguiente comando para registrar el paquete en el nodo devDependencies:

//安装指定的包,并记录到devDependencies节点中
npm i 包名-D
//注意:上述命令是简写形式,等价于卜面完整的写法:
npm install 包名--save-dev
npm i webpack -D

3.4 Resuelva el problema de la velocidad de descarga de paquetes lenta

1. ¿Por qué la velocidad de descarga es lenta?

Cuando se usa npm para descargar paquetes, el valor predeterminado es descargar desde el servidor https://registry.npmjs.org/ en el extranjero. En este momento, la transmisión de datos de la red debe pasar a través de un cable óptico submarino largo, por lo que la descarga del paquete la velocidad será muy lenta.

Lectura adicional: cable óptico submarino:

2. Servidor espejo Taobao NPM

Por favor agregue la descripción de la imagen.

Taobao ha construido un servidor en China para sincronizar paquetes de servidores oficiales extranjeros a servidores nacionales y luego proporcionar servicios de subcontratación en China. Esto mejora enormemente la velocidad de descarga de paquetes.

Extensiones:

La duplicación es una forma de almacenamiento de archivos. Los datos de un disco tienen una copia idéntica en otro disco, que es una duplicación.

3. Cambie la fuente espejo del paquete de npm

La fuente reflejada del paquete se refiere a la dirección del servidor del paquete.

#查看当前的下包地址
npm config get registry
#将下包的镜像地址切换为淘宝镜像源
npm config set registry=http://registry.npm.taobao.org/
#检测镜像源是否下载成功
npm config get registry
4. nrm

Para cambiar más convenientemente la fuente de la imagen del paquete, podemos instalar la herramienta nrm y usar el comando de terminal proporcionado por nrm para ver y cambiar rápidamente la fuente de la imagen del paquete.

#通过npm包管理器,讲npm安装为全局可用的工具
npm i nrm -g
#查看所有可用的镜像源
nrm ls
#将下包的镜像源切换为taobao镜像
nrm use taobao

3.5 Clasificación de bultos

Los paquetes descargados mediante la herramienta de administración de paquetes npm se dividen en dos categorías, a saber:

  • paquete de proyecto
  • paquete global
1. Paquete de proyecto

Los paquetes que se instalan en el directorio node_modules del proyecto son paquetes de proyecto.

Los paquetes de proyectos se dividen en dos categorías, a saber:

  • Paquetes de dependencia de desarrollo (los paquetes registrados en el nodo devDependencies solo se usarán durante el desarrollo)

  • Paquetes de dependencias principales (los paquetes registrados en el nodo de dependencias se utilizarán durante el desarrollo y después de que el proyecto esté en línea)

  • npm i 包名 -D #开发依赖包(记录到devDependencies 节点下)
    npm i 包名    #核心依赖包(被记录到 dependencies 节点下)
    
2. Paquete global

Al ejecutar el comando npm install, si se proporciona el parámetro -g, el paquete se instalará como un paquete global.

El paquete global se instalará en el directorio C:\Users\user directorio\AppData\Roaming\npm\node_modules.

Por favor agregue la descripción de la imagen.

Aviso:

① Solo es necesario instalar globalmente los paquetes de herramientas. Porque proporcionan comandos de terminal útiles.

② Para determinar si un paquete debe instalarse globalmente antes de poder usarse, puede consultar las instrucciones de uso oficiales.

3. i5ting_toc

i5ting_toc es una pequeña herramienta que puede convertir documentos md en páginas html, los pasos a utilizar son los siguientes:

# 将i5ting _toc安装为全局包
npm install -g i5ting_toc
# 调用i5ting_toc,轻松实现md 转 html 的功能
i5ting_toc -f 要转换的md文件路径 -o

3.6 Estructura del paquete estándar

Después de comprender el concepto de paquete y cómo descargarlo y usarlo, echemos un vistazo más profundo a la estructura interna del paquete.

Un paquete estandarizado y su estructura deben cumplir los tres requisitos siguientes:

①El paquete debe existir en un directorio separado.

②El directorio de nivel superior del paquete debe contener el archivo de configuración de administración de paquetes package.json

③package.json debe contener los tres atributos nombre, versión y principal, que representan respectivamente el nombre, el número de versión y la entrada del paquete.

Nota: Los tres requisitos anteriores son el formato que debe cumplir una estructura de paquete estandarizada. Para obtener más restricciones, puede consultar el siguiente sitio web:

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

3.7 Desarrolla tu propio paquete

1. Funciones a implementar

① Formatear fecha

② Escapar de caracteres especiales en HTML

③ Restaurar caracteres especiales en HTML

1. Funciones a implementar
// 导入自己的包
const utils = require('utils')


// 转移html中的特殊字符
const htmlStr = `<h1 style='color: red'>你好!&copy;<span>小黄</span></h1>`
const str = utils.htmlEscape(htmlStr)
console.log(str)

// 还原html中的特殊字符
const rawHtml = utils.htmlUnEscape(str)
console.log(rawHtml)
2. Estructura básica del paquete de inicialización.

①Cree una nueva carpeta itheima-tools como directorio raíz del paquete

②En la carpeta itheima-tools, cree los siguientes tres archivos:

  • package.json (archivo de configuración de gestión de paquetes)
  • index.js (archivo de entrada del paquete)
  • README.md (documentación del paquete)
3. Inicializar paquete.json
{
    
    
    "name": "suz-tools",
    "version": "1.0.0",
    "main": "index.js",
    "description": "提供了格式化时间、HTMLEscape相关的功能",
    "keywords": [
        "dateFormat",
        "secape"
    ],
    "license": "ISC"
}

Para obtener más información sobre el acuerdo de licencia, consulte https://www.jianshu.com/p/86251523e898

4. Defina el método para formatear la hora en index.js.
// 这是包的入口文件
// 定义格式化时间的函数
function dateFormat(dateStr) {
    
    
    const dt = new Date(dateStr)

    const y = dt.getFullYear()
    const m = padZero(dt.getMonth() + 1)
    const d = padZero(dt.getDate())


    const hh = padZero(dt.getHours())
    const mm = padZero(dt.getMinutes())
    const ss = padZero(dt.getSeconds())

    return `${
      
      y}-${
      
      m}-${
      
      d} ${
      
      hh}:${
      
      mm}:${
      
      ss}`
}


// 定义补零函数
function padZero(n) {
    
    
    return n > 9 ? n : '0' + n
}


// 向外暴露需要的成员
module.exports = {
    
    
    dateFormat
}
5. Defina el método para escapar de HTML en index.js
function htmlEscape(htmlStr) {
    
    
    return htmlStr.replace(/<|>|"|&/g, (match) => {
    
    
        switch (match) {
    
    
            case '<':
                return '&lt;'
            case '>':
                return '&gt;'
            case '"':
                return '&quot;'
            case '&':
                return '&amp;'
        }
    })
}
6. Defina el método para restaurar HTML en index.js
function htmlUnEscape(Str) {
    
    
    return Str.replace(/&lt;|&gt;|'&quot;|&amp;/g, (match) => {
    
    
        switch (match) {
    
    
            case '&lt;':
                return '<'
            case '&gt;':
                return '>'
            case '&quot;':
                return '"'
            case '&amp;':
                return '&'
        }
    })
}
7. Modularizar y dividir diferentes funciones

①Divida la función de formatear la hora en src -> dateFormat.js

②Divida la función de procesar cadenas HTML en src -> htmlEscape.js

③En index.js, importe dos módulos para obtener los métodos que deben compartirse externamente.

④En index.js, use module.exports para compartir los métodos correspondientes.

8. Escribir la documentación del paquete.

El archivo README.md en el directorio raíz del paquete es la documentación de uso del paquete. A través de él, podemos escribir las instrucciones de uso del paquete en formato Markdown por adelantado para comodidad del usuario.

No existen requisitos obligatorios sobre qué contenido debe escribirse en el archivo README, siempre y cuando la función, el uso, las precauciones, etc. del paquete se puedan describir claramente.

El documento README.md del paquete que creamos contendrá los siguientes 6 elementos:

Método de instalación, método de importación, tiempo de formateo, escape de caracteres especiales en HTML, restauración de caracteres especiales en HTML, acuerdo de código abierto

3.8 Paquete de lanzamiento

1. Registre una cuenta npm

①Visite el sitio web https://www.npmjs.com/ y haga clic en el botón de registro para ingresar a la interfaz de usuario de registro.

② Complete la información relacionada con la cuenta: nombre completo, correo electrónico público, nombre de usuario, contraseña

③Haga clic en el botón Crear una cuenta para registrar una cuenta

④Inicie sesión en su correo electrónico y haga clic en el enlace de verificación para verificar su cuenta.

2. Inicie sesión en la cuenta npm

Una vez completado el registro de la cuenta npm, puede ejecutar el comando de inicio de sesión npm en la terminal. Después de ingresar el nombre de usuario, la contraseña y el correo electrónico en secuencia, podrá iniciar sesión correctamente.

Nota: antes de ejecutar el comando de inicio de sesión de npm, primero debe cambiar la dirección del servidor del paquete al servidor oficial de npm. De lo contrario, la publicación del paquete fallará.

3. Publicar el paquete en npm

Después de cambiar la terminal al directorio raíz del paquete, ejecute el comando npm Publish para publicar el paquete en npm (nota: los nombres de los paquetes no pueden ser los mismos).

Por favor agregue la descripción de la imagen.

4. Eliminar paquetes publicados

Ejecute el comando npm unpublish package name --force para eliminar el paquete publicado de npm.

Aviso:

①El comando npm unpublish solo puede eliminar paquetes publicados dentro de las 72 horas.

②Los paquetes eliminados por npm unpublish no pueden volver a publicarse dentro de las 24 horas.

③ ¡Tenga cuidado al publicar paquetes e intente no publicar paquetes sin sentido en npm!

Mecanismo de carga del módulo

4.1 Priorizar la carga desde la caché

Los módulos se almacenan en caché después de cargarse por primera vez. Esto también significa que llamar a require() varias veces no hará que el código del módulo se ejecute varias veces.

Nota: Ya sean módulos integrados, módulos definidos por el usuario o módulos de terceros, se cargarán primero desde la memoria caché, lo que mejorará la eficiencia de carga del módulo.

4.2 Mecanismo de carga de módulos integrados

Los módulos integrados son módulos proporcionados oficialmente por Node.js y tienen la máxima prioridad de carga.

Por ejemplo, require('fs') siempre devuelve el módulo fs integrado, incluso si hay un paquete con el mismo nombre en el directorio node_modules llamado fs.

4.3 Mecanismo de carga de módulos personalizados

Cuando utilice require() para cargar un módulo personalizado, debe especificar un identificador de ruta que comience con ./ o .../. Al cargar un módulo personalizado, si no se especifica ningún identificador de ruta como ./ o .../, node lo cargará como un módulo integrado o un módulo de terceros.

Al mismo tiempo, cuando se utiliza require() para importar un módulo personalizado, si se omite la extensión del archivo, Node.js intentará cargar los siguientes archivos en orden:

①Cargar según el nombre exacto del archivo

②Complete la extensión .js para cargar

③Complete la extensión .json para cargar

④Complete la extensión .node para cargar

⑤La carga falló y el terminal informó un error

4.4 Mecanismo de carga de módulos de terceros

Si el identificador del módulo pasado a require() no es un módulo integrado y no comienza con './' o '.../', Node.js intentará cargar desde la carpeta /node_modules, comenzando desde la carpeta actual. directorio principal del módulo Módulos de terceros.

Si no se encuentra el módulo de terceros correspondiente, se mueve al directorio principal un nivel superior y se carga hasta el directorio raíz del sistema de archivos.

Por ejemplo, suponiendo que se llame a require('tools') en el archivo 'C:\Users\itheima\project\foo.js', Node.js buscará en el siguiente orden:

① C:\Usuarios\itheima\project\node_modules\tools

② C:\Usuarios\itheima\node_modules\herramientas

③ C:\Usuarios\node_modules\herramientas

④ C:\node_modules\herramientas

4.5 Directorios como módulos

Al pasar un directorio como identificador de módulo a require() para cargar, existen tres métodos de carga:

①Busque un archivo llamado package.json en el directorio que se está cargando y busque el atributo principal, que sirve como punto de entrada para la carga de require().

② Si no hay ningún archivo package.json en el directorio, o la entrada principal no existe o no se puede analizar, Node.js intentará cargar el archivo index.js en el directorio.

③Si los dos pasos anteriores fallan, Node.js imprimirá un mensaje de error en la terminal, informando que falta el módulo: Error: No se puede encontrar el módulo 'xxx'

Expresar

Primera introducción a Express

1.1 Introducción a Express

1. ¿Qué es expreso?

Concepto oficial: Express es un marco de desarrollo web rápido, abierto y minimalista basado en la plataforma Node.js.

Comprensión popular: Express funciona de manera similar al módulo http integrado de Node.js y se utiliza especialmente para crear servidores web.

La esencia de Express: es un paquete de terceros en npm que proporciona un método conveniente para crear rápidamente un servidor web.

Sitio web oficial chino de Express: http://www.expressjs.com.cn/

2. Obtenga más información sobre Express

Pensando: ¿Es posible crear un servidor web sin utilizar Express?

Respuesta: Sí, puede utilizar el módulo http nativo proporcionado por Node.js.

Pensamiento: si ya eres bueno, ¿por qué deberías ser brillante (con el módulo http incorporado, por qué sigues usando Express)?

Respuesta: El módulo http incorporado es muy complicado de usar y la eficiencia del desarrollo es baja; Express está encapsulado aún más en función del módulo http incorporado, lo que puede mejorar en gran medida la eficiencia del desarrollo.

Pensando: ¿Cuál es la relación entre el módulo integrado http y Express?

Respuesta: Similar a la relación entre Web API y jQuery en el navegador. Este último se encapsula aún más en función del primero.

3. Qué puede hacer Express

Para los programadores front-end, los dos servidores más comunes son:

  • Servidor de sitio web: un servidor que proporciona específicamente recursos de páginas web externas.
  • Servidor de interfaz API: un servidor que proporciona específicamente interfaces API al mundo exterior.

Con Express, podemos crear fácil y rápidamente un servidor de sitio web o un servidor de interfaz API.

1.2 Uso básico de Express

1. Instalación

En el directorio donde se encuentra el proyecto, ejecute el siguiente comando de terminal para instalar express en el proyecto para su uso:

npm i [email protected]
2. Cree un servidor web básico
// 导入express
const express = require('express')
    // 创建web服务器
const app = express()
    // 启动web服务器
app.listen(80, () => {
    
    
    console.log('express server running at http://127.0.0.1');
})
3. Escuche las solicitudes GET

A través del método app.get (), puede monitorear la solicitud GET del cliente. El formato de sintaxis específico es el siguiente:

//参数1: 客户端请求URL	地址
//参数2: 请求对应的出来函数
//       req: 请求对象(包含了与请求相关的属性与方法)
//       res: 响应对象(包含了与响应相关的属性与方法)
app.get('请求URL'function(req,res) {
    
     /*处理函数*/ })
4. Escuche las solicitudes POST

A través del método app.post (), puede monitorear la solicitud POST del cliente. El formato de sintaxis específico es el siguiente:

app.post('请求URL'function(req,res) {
    
     /*处理函数*/ })
5. Responder el contenido al cliente

Mediante el método res.send(), el contenido procesado se puede enviar al cliente:

// 导入express
const express = require('express')
    // 创建web服务器
const app = express()

// 监听get、post请求,并向客户端响应具体的内容
app.get('/user', (req, res) => {
    
    
    // 调用express提供的rend.send()方法,向客户端响应一个json对象
    res.send({
    
     name: 'zs', age: 20, gender: '男' })
})

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


// 启动web服务器
app.listen(80, () => {
    
    
    console.log('express server running at http://127.0.0.1');
})
6. Obtenga los parámetros de consulta incluidos en la URL.

A través del objeto req.query, puede acceder a los parámetros enviados por el cliente al servidor en forma de cadenas de consulta:

app.get( ' '. (req,res)=>{
    
     
//req.query 默认是一个空对象
//客户端使用?name=zs&age=20这种查询字符串形式,发送到服务器的参数,
//可以通过req.query 对象访问到。例投:
// req.query.name req.query.age
console.log(req.query)
})

7. Obtenga parámetros dinámicos en la URL

A través del objeto req.params, puede acceder a la URL y hacer coincidir los parámetros dinámicos a través de:

//URL地址中,可以通过:参数名  的形式,匹配动态参数值
app.get('/user/:id',(req,res) => {
	//req.params 默认为一个空对象
	//里面存放着通过:动态匹配到参数值
	console.log(req.params)
})

1.3 Alojamiento de recursos estáticos

1. expreso.estático()

Express proporciona una función muy fácil de usar llamada express.static(). A través de ella, podemos crear fácilmente un servidor de recursos estático. Por ejemplo, a través del siguiente código, podemos usar el siguiente código para almacenar imágenes, archivos CSS, y archivos JavaScript en el directorio público. Abierto al público:

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

Ahora puede acceder a todos los archivos en el directorio público:

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

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

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

Nota: Express busca archivos en el directorio estático especificado y proporciona rutas de acceso a recursos al mundo exterior.

Por tanto, el nombre del directorio donde se almacenan los archivos estáticos no aparecerá en la URL.

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

// 在这里,调用express.static方法,快速对外提供静态资源
app.use(express.static('./files'))


app.listen(80, () => {
    
    
    console.log('express server running at http://127.0.0.1')
})
2. Alojar varios directorios de recursos estáticos

Si desea alojar varios directorios de recursos estáticos, llame a la función express.static() varias veces:

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

Al acceder a archivos de recursos estáticos, la función express.static() encontrará los archivos necesarios según el orden en que se agregan los directorios.

3. Prefijo de ruta de montaje

Si desea montar el prefijo de ruta antes de la ruta de acceso a recursos estáticos administrados, puede utilizar el siguiente método:

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

Ahora, puede acceder a archivos en el directorio público a través de direcciones con el prefijo /public:

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

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

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

1.4 nodemonio

1. ¿Por qué utilizar nodemon?

Al escribir y depurar proyectos de Node.js, si modifica el código del proyecto, deberá cerrarlo manualmente con frecuencia y luego reiniciarlo, lo cual es muy engorroso.

Ahora, podemos usar la herramienta nodemon (https://www.npmjs.com/package/nodemon), que puede monitorear los cambios en los archivos del proyecto. Cuando se modifica el código, nodemon reiniciará automáticamente el proyecto por nosotros, lo cual es muy conveniente Desarrollo y depuración.

2. Instalar nodemon

En la terminal, ejecute el siguiente comando para instalar nodemon como una herramienta disponible globalmente:

npm install -g nodemon
3. Usa nodemon

Al escribir una aplicación de sitio web basada en Node.js, la forma tradicional es ejecutar el comando node app.js para iniciar el proyecto. La desventaja de esto es que después de modificar el código, el proyecto debe reiniciarse manualmente.

Ahora, podemos reemplazar el comando node con el comando nodemon y usar nodemon app.js para iniciar el proyecto. La ventaja de esto es que después de modificar el código, nodemon lo monitoreará, logrando así el efecto de reiniciar automáticamente el proyecto.

node app.js
#将上面的终端命令,替换为下面的终端命令,既可实现自动重启项目的效果
nodemon app.js

Enrutamiento expreso

2.1 El concepto de enrutamiento

1. ¿Qué es el enrutamiento?

En términos generales, el enrutamiento es una relación de mapeo.

2. Enrutamiento en Express

En Express, el enrutamiento se refiere a la relación de mapeo entre las solicitudes del cliente y las funciones de procesamiento del servidor.

El enrutamiento en Express se divide en tres partes, a saber, el tipo de solicitud, la dirección URL solicitada y la función de procesamiento, el formato es el siguiente:

app.METHOD(PATH,HANDLER)
4. Ejemplo de enrutamiento en Express
//匹配get请求,请求url为/
app.get('/',function(req,res) {
	res.send('hello')
})

//匹配post请求,请求url为/
app.post('/',function(req,res) {
	res.send('Get a post request')
})
5. Proceso de coincidencia de rutas

Siempre que una solicitud llega al servidor, primero debe coincidir con la ruta y solo después de que la coincidencia sea exitosa, se llamará a la función de procesamiento correspondiente.

Al hacer coincidir, la coincidencia se realizará en el orden de las rutas. Si el tipo de solicitud y la URL solicitada coinciden con éxito al mismo tiempo, Express transferirá la solicitud a la función correspondiente para su procesamiento.

Por favor agregue la descripción de la imagen.

Notas sobre la coincidencia de rutas:

①Coincidir según el orden definido

②La función de procesamiento correspondiente se llamará solo cuando el tipo de solicitud y la URL solicitada coincidan correctamente al mismo tiempo.

2.2 Uso de enrutamiento

1. El uso más sencillo

La forma más sencilla de utilizar el enrutamiento en Express es montar el enrutamiento en la aplicación. El código de muestra es el siguiente:

const express = require('express')
//创建web服务器,命名为app
const app = express()

//挂载路由
app.get('/',(req,res) => {
    
    
	res.send('hello')
})
app.post('/',(req,res) => {
    
    
	res.send('Post request')
})

//启动web服务器
app.listen(80,() => {
    
    
	console.log('express server running at http://127.0.0.1')
})
2. Enrutamiento modular

Para facilitar la gestión modular de rutas, Express no recomienda montar rutas directamente en la aplicación, pero recomienda extraer rutas en módulos separados.

Los pasos para extraer el enrutamiento en un módulo separado son los siguientes:

①Cree el archivo .js correspondiente al módulo de enrutamiento

②Llame a la función express.Router() para crear un objeto de enrutamiento

③Montar rutas específicas al objeto de enrutamiento

④Utilice module.exports para compartir objetos de enrutamiento externamente

⑤Utilice la función app.use() para registrar el módulo de enrutamiento

3. Crear módulo de enrutamiento
// 导入express
const express = require('express')
    // 创建路由对象
const router = express.Router()

// 挂载获取用户列表的路由
router.get('/user/list', function(req, res) {
    
    
    res.send('Get user list')
})

// 挂载添加用户的路由
router.post('/user/list', function(req, res) {
    
    
    res.send('Add new user')
})

// 向外导出路由对象
module.exports = router
4. Registre el módulo de enrutamiento
const express = require('express')
const { expr } = require('jquery')
const app = express()

//1.导入路由模块
const router = require('./05-router')

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

app.listen(80, () => {
    console.log('http://127.0.0.1')
})
5. Agregar prefijo al módulo de enrutamiento

De manera similar al montaje unificado de prefijos de acceso para recursos estáticos cuando se alojan recursos estáticos, la forma en que el módulo de enrutamiento agrega prefijos también es muy simple:

//1.导入路由模块
const router = require('./05-router')

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

middleware exprés

3.1 Concepto de middleware

1. ¿Qué es el software intermedio?

Middleware se refiere específicamente a los enlaces de procesamiento intermedio de los procesos comerciales.

2. Ejemplos de la vida real

Cuando se tratan aguas residuales, generalmente existen tres enlaces de tratamiento para garantizar que las aguas residuales tratadas cumplan con los estándares de descarga.

Por favor agregue la descripción de la imagen.

Estos tres enlaces de procesamiento intermedio para el tratamiento de aguas residuales pueden denominarse middleware.

3. Proceso de llamada de middleware exprés

Cuando una solicitud llega al servidor Express, se pueden llamar continuamente a varios middlewares para preprocesar la solicitud.

Por favor agregue la descripción de la imagen.

4. Formato de middleware exprés

El middleware Express es esencialmente una función de procesamiento de funciones. El formato del middleware Express es el siguiente:

Por favor agregue la descripción de la imagen.

Nota: La lista de parámetros formales de la función de middleware debe contener el siguiente parámetro. La función de procesamiento de enrutamiento solo contiene req y res.

5. El papel de la siguiente función.

La siguiente función es la clave para realizar la invocación continua de múltiples middlewares, lo que significa transferir la relación de flujo al siguiente middleware o ruta.

Por favor agregue la descripción de la imagen.

3.2 Primera experiencia con el middleware Express

1. Definir funciones de middleware

Puede definir la función de middleware más simple de la siguiente manera:

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. Middleware eficaz a nivel mundial

Cualquier solicitud iniciada por el cliente activará el middleware después de que llegue al servidor, lo que se denomina middleware globalmente efectivo.

Al llamar a app.use (función de middleware), puede definir un middleware globalmente efectivo. El código de muestra es el siguiente:

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

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

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

app.get('/', (req, res) => {
    
    
    console.log('调用了/这个路由')
    res.send('home page')
})

app.get('/user', (req, res) => {
    
    
    console.log('调用了/user这个路由')
    res.send('User page')
})

app.listen(80, () => {
    
    
    console.log('http://127.0.0.1')
})
3. Definir una forma simplificada de middleware global.
//全局生效的中间件
app.use(function(req,res,next) {
    
    
	console.log('这是一个最简单的中间件函数')
	next()
})
4. El papel del middleware

Varios middlewares comparten el mismo requisito y resolución. Con base en esta característica, podemos agregar de manera uniforme atributos o métodos personalizados a los objetos req o res en el middleware ascendente para su uso por el middleware o enrutamiento descendente.

Por favor agregue la descripción de la imagen.

5. Definir múltiples middleware globales

Puede utilizar app.use() para definir varios middlewares globales sucesivamente. Una vez que la solicitud del cliente llega al servidor, se llamará en el orden definido por el middleware. El código de muestra es el siguiente:

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

// 定义第一个全局中间件
app.use((req, res, next) => {
    
    
    console.log('调用了第一个全局中间件')
    next()
})

// 定义第二个全局中间件
app.use((req, res, next) => {
    
    
    console.log('调用了第二个全局中间件')
    next()
})

// 定义一个路由
app.get('/user', (req, res) => {
    
    
    res,
    send('USer page')
})



app.listen(80, () => {
    
    
    console.log('http://127.0.0.1')
})
6. Middleware eficaz a nivel local

El middleware que no utiliza app.use () se denomina middleware local efectivo. El código de muestra es el siguiente:

//定义中间件函数mw1
const mw1 = function(req,res,next) {
    
    
	console.log('这是中间件函数')
	next()
}
//mw1这个中间件只在“当前路由中生效”,这种用法属于“局部生效中间件”
app.get('/',mw1,function(req,res){
    
    res.const express = require('express')
const app = express()

//定义中间件函数mw1
const mw1 = function(req, res, next) {
    
    
        console.log('这是局部中间件函数')
        next()
    }
    //mw1这个中间件只在“当前路由中生效”,这种用法属于“局部生效中间件”
app.get('/', mw1, function(req, res) {
    
     res.send('Home page') })

//mw1 这个中间件不会影响下面这个路由
app.get('/user', function(req, res) {
    
    
    res.send('User page')
})

app.listen(80, function() {
    
    
    console.log('http://127.0.0.1');
})send('Home page')})

//mw1 这个中间件不会影响下面这个路由
app.get('/user',function(req,res){
    
    res.send('User page')})
7. Definir múltiples middleware locales

Se pueden utilizar varios middleware locales en el enrutamiento de las dos formas equivalentes siguientes:

//以下两种写法是“完全等价”的,可根据自己的爱好,选择一种方式进行使用
app.get('/', mw1,mw2, function(req, res) {
    
     res.send('Home page') })
app.get('/',[ mw1,mw2], function(req, res) {
    
     res.send('Home page') })
8. Comprenda cinco cosas a tener en cuenta al utilizar middleware

① Asegúrese de registrar el middleware antes de enrutar

②Las solicitudes enviadas desde el cliente se pueden procesar llamando continuamente a varios middlewares.

③Después de ejecutar el código comercial del middleware, no olvide llamar a la función next()

④Para evitar confusión en la lógica del código, no escriba código adicional después de llamar a la función next().

⑤Cuando se llaman continuamente varios middlewares, los objetos req y res se comparten entre varios middlewares.

3.3 Clasificación del middleware

Para que todos comprendan y recuerden más fácilmente el uso del middleware, Express divide oficialmente el uso común del middleware en 5 categorías principales, a saber:

① Middleware a nivel de aplicación

② Middleware de nivel de enrutamiento

③ Middleware de nivel de error

④Middleware integrado Express

⑤Middleware de terceros

1. Middleware a nivel de aplicación

El middleware vinculado a la instancia de la aplicación a través de app.use() o app.get() o app.post() se denomina middleware a nivel de aplicación. El ejemplo de código es el siguiente:

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

//应用级别中间件(局部中间件)
app.get('/' , mw1 ,(req,res) => {
	res.send('Home page')
})
2. Middleware a nivel de enrutamiento

El middleware vinculado a instancias de express.Router() se denomina middleware a nivel de ruta. Su uso no es diferente del middleware a nivel de aplicación. Sin embargo, el middleware a nivel de aplicación está vinculado a la instancia de la aplicación y el middleware a nivel de ruta está vinculado a la instancia del enrutador. El ejemplo de código es el siguiente:

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

//路由级别的中间件
router.user(function(req,res,next) {
    
    
	console.log('Time:',Date.now())
	next()
})

app.use('/',router)
3. Middleware de nivel incorrecto

La función del middleware de nivel de error: se utiliza especialmente para capturar errores anormales que ocurren durante todo el proyecto, evitando así que el proyecto falle de manera anormal.

Formato: la función de procesamiento de funciones del middleware de nivel de error debe tener 4 parámetros formales, y el orden de los parámetros formales de adelante hacia atrás es (err, req, res, next).

app.get('/',function(req,res) {
    
    		   //1.路由
	throw new Error('服务器内部发生错误') //1.1抛出一个自定义错误
	res.send('Home page')
})

app.use(function(err,req,res,next) {
    
    	//2.错误级别的中间件
	console.log('发生错误' + err.message)//2.1在服务器打印错误消息
	res.send('Error' + err.message)		//2.2向客户端响应错误相关的内容
})

Nota: ¡El middleware de nivel de error debe registrarse después de todas las rutas!

La función de procesamiento de funciones del middleware de nivel de error debe tener 4 parámetros formales, cuyo orden de adelante hacia atrás es (err, req, res, next).

Nota: ¡El middleware de nivel de error debe registrarse después de todas las rutas!

4. Middleware integrado exprés

Desde la versión Express 4.16.0, Express ha incorporado 3 middleware de uso común, lo que ha mejorado enormemente la eficiencia de desarrollo y la experiencia de los proyectos Express:

① express.static es un middleware integrado que aloja rápidamente recursos estáticos, como archivos HTML, imágenes, estilos CSS, etc. (sin compatibilidad)

② express.json analiza los datos del cuerpo de la solicitud en formato JSON (con compatibilidad, solo disponible en la versión 4.16.0+)

③ express.urlencoded analiza los datos del cuerpo de la solicitud en formato codificado en URL (compatible, solo disponible en la versión 4.16.0+)

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

// 除错误中间件,其他中间件的在路由之前进行配置
app.use(express.json())
    // 通过express.urlencoded解析
app.use(express.urlencoded({
    
     extended: false }))

app.post('/user', (req, res) => {
    
    
    // 在服务器,可以使用req.body这个属性,来接收客户端发送过来的请求
    // 默认情况下,如果不配置解析表单的中间件,则req.body为undefined
    console.log(req.body)
    res.send('ok')
})

app.post('/book', (req, res) => {
    
    
    console.log(req.body)
    console.log('ok')
})



app.listen(80, () => {
    
    
    console.log('express server running at http://127.0.0.1')
})
5. Middleware de terceros

No está oficialmente integrado en Express, pero es un middleware desarrollado por un tercero, llamado middleware de terceros. En el proyecto, puede descargar y configurar middleware de terceros a pedido, mejorando así la eficiencia del desarrollo del proyecto.

Por ejemplo: en versiones anteriores a [email protected], el analizador corporal de middleware de terceros se usaba a menudo para analizar los datos del cuerpo de la solicitud. Los pasos de uso son los siguientes:

①Ejecute npm install body-parser para instalar middleware

②Utilice require para importar middleware

③Llame a app.use() para registrarse y usar el middleware

Nota: El middleware express.urlencoded integrado de Express se encapsula aún más en función del analizador corporal del middleware de terceros.

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

//1.导入解析表单数据的中间件body-parser
const parser = require('body-parser')
    // 使用app.use注册中间件
app.use(parser.urlencoded({
    
     extended: false }))


app.post('/user', (req, res) => {
    
    
    console.log(req.body)
    res.send('ok')
})

app.listen(80, () => {
    
    
    console.log('express server running at http://127.0.0.1')
})

3.4 Middleware personalizado

1. Descripción de requisitos y pasos de implementación.

Simule manualmente un middleware similar a express.urlencoded para analizar los datos del formulario enviados al servidor a través de POST.

Pasos de implementación:

①Definir middleware

②Escuche el evento de datos de req

③Escuche el evento final de req

④Utilice el módulo de cadena de consulta para analizar los datos del cuerpo de la solicitud

⑤Monte el objeto de datos analizado como req.body

⑥Encapsular middleware personalizado en módulos

2. Definir middleware

Utilice app.use () para definir middleware globalmente efectivo, el código es el siguiente:

app.use(function(req,res,next) {
	//中间件的业务逻辑
})
3. Escuche el evento de datos de req.

En el middleware, debe escuchar el evento de datos del objeto req para obtener los datos enviados por el cliente al servidor.

Si la cantidad de datos es demasiado grande para enviarla a la vez, el cliente cortará los datos y los enviará al servidor en lotes. Por lo tanto, el evento de datos puede activarse varias veces. Cada vez que se activa el evento de datos, los datos obtenidos son solo una parte de los datos completos y los datos recibidos deben fusionarse manualmente.

//定义变量,用来存储客户端发送过来的请求体数据
let str = ''
//监听 req 的 data 事件(客户端发送过来的请求体数据)
req.on('data',(chunk) => {
    
    
	//拼接请求体数据,隐式转换为字符串
	str += chunk
})
4. Escuche el evento final de req.

Cuando se reciben los datos del cuerpo de la solicitud, el evento de finalización de la solicitud se activará automáticamente.

Por lo tanto, podemos obtener y procesar los datos completos del cuerpo de la solicitud al finalizar la solicitud. El código de muestra es el siguiente:

//监听req对象的end时间(请求体发送完毕后自动触发)
req.on('end',() => {
    
    
	//打印完整的请求体数据
	console.log(str)
	//T0D0:把字符串格式的请求体数据,解析成对象格式
})
5. Utilice el módulo de cadena de consulta para analizar los datos del cuerpo de la solicitud.

Node.js tiene un módulo de cadena de consulta incorporado, que se utiliza especialmente para procesar cadenas de consulta. A través de la función parse() proporcionada por este módulo, puede analizar fácilmente la cadena de consulta en formato de objeto. El código de muestra es el siguiente:

//导入处理querystring的node.js内置模块
const qs = require('querystring')

//调用qs.parse()方法,把查询字符串解析为对象
const body = qs.parse(str)
6. Monte el objeto de datos analizado como req.body

El middleware ascendente y el middleware y el enrutamiento descendente comparten los mismos requisitos y resolución. Por lo tanto, podemos montar los datos analizados como un atributo personalizado de req y llamarlo req.body para uso posterior. El código de muestra es el siguiente:

//导入处理querystring 的Node.js内置模块
const qs = require( ' querystring ')
//调用qs.parse()方法,把查询字符串解析为对象
const body = qs.parse( str)

7. Encapsular middleware personalizado en módulos

Para optimizar la estructura del código, podemos encapsular la función de middleware personalizada en un módulo independiente. El código de muestra es el siguiente:

req.on( 'end ',() => {
const body = qs.parse(str) 
//调用qs.parse()方法,把查询字符串解析为对象
req.body = body
//将解析出来的请求体对象,挂载为req.body属性
next()
//最后,一定要调用next()函数,执行后续的业务逻辑
})

Utilice Express para escribir la interfaz.

4.1 Crear un servidor básico

const express = require('express')

const app = express()

app.listen(80, function() {
    console.log('express server running at http://127.0.0.1')
})

4.2 Crear módulo de enrutamiento API

const express = require('express')

const app = express()



app.listen(80, () => {
    console.log('express server running at http://127.0.0.1')
})

module.exports = router

4.3 Escribir interfaz GET

// 在这里挂载对应的路由
router.get('/get', (req, res) => {
    // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
    const query = req.query
        // 调用 res.send() 方法,向客户端响应处理的结果
    res.send({
        status: 0, // 0 表示处理成功,1 表示处理失败
        msg: 'GET 请求成功!', // 状态的描述
        data: query, // 需要响应给客户端的数据
    })
})

4.4 Escritura de la interfaz POST

router.post('/post', (req, res) => {
    // 通过req.body 获取请求体中包含的url-encoded 格式的数据
    const body = req.body
        // 调用 res.send() 方法,向客户端响应处理的结果
    res.send({
        status: 0, // 0 表示处理成功,1 表示处理失败
        msg: 'POST 请求成功!', // 状态的描述
        data: body, // 需要响应给客户端的数据
    })
})

// express模块
app.use(express.urlencoded({ extended: false }))

Nota: Si desea obtener los datos del cuerpo de la solicitud en formato codificado en URL, debe configurar el middleware app.use(express.urlencoded({ extended: false }))

4.5 CORS intercambio de recursos entre dominios

1. Problemas de interfaz entre dominios

Las interfaces GET y POST que acabamos de escribir tienen un problema grave: no admiten solicitudes entre dominios.

Hay dos soluciones principales para resolver el problema de la interfaz entre dominios:

① CORS (solución convencional, recomendada)

② JSONP (solución defectuosa: solo admite solicitudes GET)

2. Utilice el middleware cors para resolver problemas entre dominios

cors es un middleware de terceros para Express. Al instalar y configurar el middleware de cors, los problemas entre dominios se pueden resolver fácilmente.

Los pasos de uso se dividen en tres pasos:

①Ejecute npm install cors para instalar middleware

②Utilice const cors = require('cors') para importar middleware

③Llame a app.use(cors()) antes del enrutamiento para configurar el middleware

3. ¿Qué es CORS?

CORS (Cross-Origin Resource Sharing, intercambio de recursos entre orígenes) consta de una serie de encabezados de respuesta HTTP, que determinan si el navegador evita que el código JS front-end obtenga recursos entre dominios.

La política de seguridad del mismo origen del navegador evita que las páginas web obtengan recursos "entre dominios" de forma predeterminada. Sin embargo, si el servidor de interfaz está configurado con encabezados de respuesta HTTP relacionados con CORS, se pueden eliminar las restricciones de acceso entre dominios del lado del navegador.

Por favor agregue la descripción de la imagen.

4. Cosas a tener en cuenta sobre CORS

①CORS se configura principalmente en el lado del servidor. El navegador del cliente no necesita realizar ninguna configuración adicional para solicitar la interfaz habilitada para CORS.

②CORS tiene compatibilidad en navegadores. Normalmente, solo los navegadores que admiten XMLHttpRequest Level2 pueden acceder a la interfaz del servidor con CORS habilitado (por ejemplo: IE10+, Chrome4+, FireFox3.5+).

5. Encabezado de respuesta CORS: Access-Control-Allow-Origin

El encabezado de respuesta puede llevar un campo Access-Control-Allow-Origin, cuya sintaxis es la siguiente:

Access-Control-Allow-Origin:<origin> | *

Entre ellos, el valor del parámetro de origen especifica la URL del dominio externo que puede acceder al recurso.

Por ejemplo, el siguiente valor de campo solo permitirá solicitudes de http://itcast.cn:

res.setHeader('Access-Control-Allow-Origin',' http://itcast.cn')

Si el valor del campo Access-Control-Allow-Origin se especifica como comodín *, significa que se permiten solicitudes de cualquier dominio. El código de muestra es el siguiente:

res.setHeader('Access-Control-Allow-Origin','*')
6. Encabezados de respuesta CORS: Access-Control-Allow-Headers

De forma predeterminada, CORS solo permite que el cliente envíe los siguientes 9 encabezados de solicitud al servidor:

Aceptar, Aceptar-Idioma, Contenido-Idioma, DPR, Enlace descendente, Guardar-Datos, Ancho de ventana gráfica, Ancho, Tipo de contenido (los valores se limitan a texto/sin formato, multiparte/datos de formulario, aplicación/x-www- formulario codificado por URL uno de los tres)

Si el cliente envía información de encabezado de solicitud adicional al servidor, el encabezado de solicitud adicional debe declararse en el lado del servidor a través de Access-Control-Allow-Headers; de lo contrario, la solicitud fallará.

//允许客户端额外向服务器发送Content-Type请求头和X-Custom-Header请求头
//注意:多个请求头之间使用英文的逗号进行分割
res.setHeader('Access-Control-Allow-Header','Content-Type,X-Custom-Header')
7. Encabezado de respuesta CORS: métodos de permiso de control de acceso

De forma predeterminada, CORS solo admite solicitudes GET, POST y HEAD iniciadas por el cliente.

Si el cliente desea solicitar recursos del servidor mediante PUT, DELETE, etc., debe especificar los métodos HTTP permitidos para la solicitud real a través de Access-Control-Alow-Methods en el lado del servidor.

El código de muestra es el siguiente:


8. Clasificación de solicitudes CORS

Cuando el cliente solicita la interfaz CORS, las solicitudes CORS se pueden dividir en dos categorías según el método de solicitud y los encabezados de solicitud, que son:

①Solicitud sencilla

②Solicitud de verificación previa

9. Solicitud sencilla

Una solicitud que cumple las dos condiciones siguientes al mismo tiempo es una solicitud simple:

① Método de solicitud: uno de GET, POST, HEAD

② La información del encabezado HTTP no excede los siguientes campos: sin campo de encabezado personalizado, Aceptar, Aceptar idioma, Idioma de contenido, DPR, Enlace descendente, Guardar datos, Ancho de ventana gráfica, Ancho, Tipo de contenido (solo tres Valores de aplicación/x -www-form-urlencoded, multipart/form-data, texto/sin formato)

10. Solicitud de verificación previa

Siempre que la solicitud cumpla alguna de las siguientes condiciones, se requiere una solicitud de verificación previa:

① El método de solicitud es un tipo de método de solicitud distinto de GET, POST y HEAD.

② El encabezado de la solicitud contiene campos de encabezado personalizados

③ Envió datos en formato aplicación/json al servidor

Antes de que el navegador se comunique formalmente con el servidor, el navegador primero enviará una solicitud de OPCIÓN de verificación previa para saber si el servidor permite la solicitud real, por lo que esta solicitud de OPCIÓN se denomina "solicitud de verificación previa". Después de que el servidor responda con éxito a la solicitud de verificación previa, enviará la solicitud real y transportará los datos reales.

11. La diferencia entre solicitudes simples y solicitudes de verificación previa

Características de las solicitudes simples: solo se produce una solicitud entre el cliente y el servidor.

Características de la solicitud de verificación previa: Se producirán dos solicitudes entre el cliente y el servidor. La solicitud real no se iniciará hasta que la solicitud de verificación previa de OPCIÓN sea exitosa.

4.6 Interfaz JSONP

1. Revisar los conceptos y características de JSONP.

Concepto: pase lateral del navegador

Características:

①JSONP no es una solicitud Ajax real porque no utiliza el objeto XMLHttpRequest.

②JSONP solo admite solicitudes GET y no admite POST, PUT, DELETE y otras solicitudes.

2. Cosas a tener en cuenta al crear una interfaz JSONP

Si se ha configurado el uso compartido de recursos entre dominios CORS en el proyecto, para evitar conflictos, se debe declarar la interfaz JSONP antes de configurar el middleware CORS. De lo contrario, la interfaz JSONP se procesará como una interfaz con CORS habilitado. El código de muestra es el siguiente:


3. Pasos para implementar la interfaz JSONP

①Obtener el nombre de la función de devolución de llamada enviada por el cliente

②Obtener los datos que se enviarán al cliente en formato JSONP

③ Según los datos obtenidos en los dos primeros pasos, empalme una cadena de llamadas a funciones

④Responda la cadena obtenida al empalmar el paso anterior al cliente

4. Código específico para implementar la interfaz JSONP

5. Utilice jQuery para iniciar solicitudes JSONP en páginas web.

Llame a la función $.ajax() para proporcionar opciones de configuración JSONP para iniciar una solicitud JSONP. El código de muestra es el siguiente:


Autenticación de identidad y base de datos

Conceptos básicos de base de datos.

1.1 ¿Qué es una base de datos?

Una base de datos es un almacén que se utiliza para organizar, almacenar y gestionar datos.

El mundo actual es un mundo de Internet lleno de datos, lleno de una gran cantidad de datos. Existen muchas fuentes de datos, como registros de viajes, registros de consumo, páginas web navegadas, mensajes enviados, etc. Además de los datos de tipo texto, las imágenes, la música y los sonidos son todos datos.

Para facilitar la gestión de datos en el mundo de Internet, existe el concepto de sistema de gestión de bases de datos (abreviatura: base de datos). Los usuarios pueden realizar operaciones como agregar, consultar, actualizar y eliminar datos en la base de datos.

1.2 Bases de datos y clasificaciones comunes

Existen muchos tipos de bases de datos en el mercado, las bases de datos más comunes son las siguientes:

  • Base de datos MySQL (actualmente la base de datos gratuita de código abierto más utilizada y popular; Community + Enterprise)
  • Base de datos Oracle (con cargo)
  • Base de datos SQL Server (con cargo)
  • Base de datos Mongodb (Comunidad + Empresa)

Entre ellas, MySQL, Oracle y SQL Server son bases de datos tradicionales (también llamadas bases de datos relacionales o bases de datos SQL), estas tres tienen el mismo concepto de diseño y uso similar.

Mongodb es un nuevo tipo de base de datos (también llamada base de datos no relacional o base de datos NoSQL), que compensa en cierta medida las deficiencias de las bases de datos tradicionales.

1.3 Estructura de organización de datos de una base de datos tradicional.

Estructura de organización de datos: se refiere a la estructura en la que se almacenan los datos.

La estructura de organización de datos de una base de datos tradicional es similar a la estructura de organización de datos en Excel.

Por lo tanto, podemos compararlo con Excel para comprender y aprender la estructura de organización de datos de las bases de datos tradicionales.

1. Estructura de organización de datos de Excel

En cada Excel, la estructura de organización de datos consta de cuatro partes: libro de trabajo, hoja de trabajo, filas de datos y columnas.

①Todo Excel se llama libro de trabajo.

②los usuarios y los libros son hojas de trabajo

③Hay 3 filas de datos en la hoja de trabajo de usuarios

④Cada fila de datos consta de 6 columnas de información

⑤Cada columna de información tiene un tipo de datos correspondiente

2. Estructura de organización de datos de la base de datos tradicional.

En las bases de datos tradicionales, la estructura organizativa de los datos se divide en cuatro partes: base de datos, tabla, fila y campo.

① La base de datos es similar a un libro de Excel.

② La tabla de datos es similar a una hoja de cálculo de Excel.

③ La fila de datos es similar a cada fila de datos en Excel

④ Los campos son similares a las columnas de Excel.

⑤ Cada campo tiene un tipo de datos correspondiente

3. La relación entre bibliotecas, tablas, filas y campos en el desarrollo real.

①En el desarrollo real de proyectos, generalmente cada proyecto corresponde a una base de datos independiente.

② Se deben almacenar diferentes datos en diferentes tablas de la base de datos, por ejemplo: los datos del usuario se almacenan en la tabla de usuarios y los datos del libro se almacenan en la tabla de libros.

③La información específica almacenada en cada tabla está determinada por los campos. Por ejemplo, podemos diseñar tres campos: identificación, nombre de usuario y contraseña para la tabla de usuarios.

④Las filas de la tabla representan cada dato específico.

Instalar y configurar MySQL

2.1 Comprender qué software relacionado con MySQL debe instalarse

Los desarrolladores solo necesitan instalar MySQL Server y MySQL Workbench para satisfacer sus necesidades de desarrollo.

  • Servidor MySQL: Software diseñado específicamente para proporcionar servicios y almacenamiento de datos.
  • MySQL Workbench: una herramienta visual de administración de MySQL a través de la cual puede operar fácilmente los datos almacenados en MySQL Server.

2.2 Instalación de MySQL en entorno Mac

El proceso de instalación de MySQL en el entorno Mac es mucho más sencillo que los pasos en el entorno Windows:

①Primero ejecute el paquete de instalación mysql-8.0.19-macos10.15-x86_64.dmg para instalar MySQL Server en el sistema Mac

②Ejecute el paquete de instalación mysql-workbench-community-8.0.19-macos-x86_64.dmg para instalar la herramienta visual MySQL Workbench en el sistema Mac

Para obtener tutoriales de instalación específicos, consulte Materiales -> MySQL para Mac -> Tutorial de instalación - Instalar MySql en el sistema Mac -> README.md

2.3 Instalación de MySQL en entorno Windows

Para instalar MySQL en un entorno Windows, solo necesita ejecutar el paquete de instalación mysql-installer-community-8.0.19.0.msi para instalar MySQL Server y MySQL Workbench en su computadora al mismo tiempo.

Para obtener tutoriales de instalación específicos, consulte Materiales -> MySQL para Windows -> Tutorial de instalación - Instalación de MySql en sistemas Windows -> README.md

Uso básico de MySQL

3.1 Utilice MySQL Workbench para administrar bases de datos

1. Conéctese a la base de datos

Por favor agregue la descripción de la imagen.

2. Comprender los componentes de la interfaz principal.

Por favor agregue la descripción de la imagen.

3. Crear base de datos

Por favor agregue la descripción de la imagen.

4. Crear tabla de datos

Por favor agregue la descripción de la imagen.

Tipo de datos Tipo de datos:

① entero entero

② cadena varchar (len)

③ tinyint(1) valor booleano

Identificación especial de campos:

① Clave principal PK (clave principal) e identificador único

② No se permite que el valor NN (no nulo) esté vacío

③ El valor UQ (único) es único

④ El valor AI (incremento automático) aumenta automáticamente

5. Escribe datos en la tabla.

Por favor agregue la descripción de la imagen.

3.2 Utilice SQL para administrar bases de datos

1. ¿Qué es SQL?

SQL (nombre completo en inglés: Structured Query Language) es un lenguaje de consulta estructurado, un lenguaje de programación que se utiliza específicamente para acceder y procesar bases de datos. Nos permite manipular los datos de la base de datos en forma de programación.

Tres puntos clave:

①SQL es un lenguaje de programación de bases de datos

②El código escrito en lenguaje SQL se llama declaración SQL

③El lenguaje SQL solo se puede utilizar en bases de datos relacionales (como MySQL, Oracle, SQL Server). Las bases de datos no relacionales (como Mongodb) no soportan el lenguaje SQL

2. ¿Qué puede hacer SQL?

① Consultar datos de la base de datos.

② Insertar nuevos datos en la base de datos.

③ Actualizar datos en la base de datos.

④ Eliminar datos de la base de datos

⑤ Puedes crear una nueva base de datos

⑥ Se pueden crear nuevas tablas en la base de datos.

⑦ Se pueden crear vistas y procedimientos almacenados en la base de datos

⑧etc…

3. Objetivos de aprendizaje de SQL

Concéntrese en dominar cómo usar SQL desde una tabla de datos:

Consultar datos (seleccionar), insertar datos (insertar en), actualizar datos (actualizar), eliminar datos (eliminar)

4 sintaxis SQL adicionales que deben dominarse:

donde condiciones y operadores, ordenar por clasificación, función contar(*)

3.3 Declaración SELECT de SQL

1. gramática

La declaración SELECT se utiliza para consultar datos de una tabla. Los resultados de la ejecución se almacenan en una tabla de resultados (llamada conjunto de resultados). El formato de sintaxis es el siguiente:


Nota: Las palabras clave en las declaraciones SQL no distinguen entre mayúsculas y minúsculas. SELECT es equivalente a seleccionar y FROM es equivalente a from.

2. SELECCIONAR * Ejemplo

Queremos seleccionar todas las columnas de la tabla de usuarios. Podemos usar el símbolo * para reemplazar el nombre de la columna. El ejemplo es el siguiente:

Por favor agregue la descripción de la imagen.

3. Ejemplo de nombre de columna SELECCIONAR

Para obtener el contenido de las columnas denominadas "nombre de usuario" y "contraseña" (de la tabla de la base de datos denominada "usuarios"), utilice la siguiente instrucción SELECT:

Por favor agregue la descripción de la imagen.

3.4 SQL INSERT INTO declaración

1. gramática

La instrucción INSERT INTO se utiliza para insertar nuevas filas de datos en la tabla de datos. El formato de sintaxis es el siguiente:


2. INSERTAR EN el ejemplo

Inserte un dato de usuario con el nombre de usuario tony stark y la contraseña 098123 en la tabla de usuarios. El ejemplo es el siguiente:


3.5 Declaración de ACTUALIZACIÓN de SQL

1. gramática

La declaración de actualización se utiliza para modificar los datos de la tabla. El formato de sintaxis es el siguiente:


2. Ejemplo de ACTUALIZAR: actualizar una columna en una fila

Actualice la contraseña del usuario con ID 7 en la tabla de usuarios a 888888. Los ejemplos son los siguientes:


3. Ejemplo de ACTUALIZAR: actualice varias columnas seguidas

Actualice la contraseña del usuario y el estado del usuario con la identificación 2 en la tabla de usuarios a admin123 y 1 respectivamente. Los ejemplos son los siguientes:


3.6 Declaración ELIMINAR SQL

1. gramática

La declaración DELETE se utiliza para eliminar filas de una tabla. El formato de sintaxis es el siguiente:


2. BORRAR ejemplo

De la tabla de usuarios, elimine el usuario con id 4. El ejemplo es el siguiente:


3.7 Cláusula WHERE de SQL

1. gramática

La cláusula WHERE se utiliza para limitar los criterios de selección. En las declaraciones SELECT, UPDATE y DELETE, puede utilizar la cláusula WHERE para limitar los criterios de selección.


2. Operadores que se pueden utilizar en la cláusula WHERE

Los siguientes operadores se pueden utilizar en la cláusula WHERE para limitar los criterios de selección: Los siguientes operadores se pueden utilizar en la cláusula WHERE para limitar los criterios de selección:

Por favor agregue la descripción de la imagen.

Nota: En algunas versiones de SQL, el operador <> se puede escribir como !=

3. Ejemplo de cláusula WHERE

Puede limitar las condiciones de consulta SELECT mediante la cláusula WHERE:


3.8 Operadores SQL Y y O

1. gramática

Y y O combinan dos o más condiciones en la subdeclaración WHERE.

Y significa que se deben cumplir varias condiciones al mismo tiempo, lo que equivale al operador && en JavaScript, como if (a!== 10 && a!== 20)

OR significa que siempre que se cumpla una condición, es equivalente al operador || en JavaScript, como if(a!== 10 || a!== 20)

2. Ejemplo de operador Y

Utilice AND para mostrar todos los usuarios con estado 0 e identificación inferior a 3:


3. Ejemplo de operador O

Utilice O para mostrar todos los usuarios con estado 1 o nombre de usuario zs:


3.9 Cláusula ORDER BY de SQL

1. gramática

La declaración ORDER BY se utiliza para ordenar el conjunto de resultados según una columna especificada.

La instrucción ORDER BY ordena los registros en orden ascendente de forma predeterminada.

Si desea ordenar los registros en orden descendente, puede utilizar la palabra clave DESC.

2. Cláusula ORDER BY - orden ascendente

Ordene los datos en la tabla de usuarios en orden ascendente según el campo de estado, el ejemplo es el siguiente:


3. Cláusula ORDER BY: ordenar en orden descendente

Ordene los datos en la tabla de usuarios en orden descendente según el campo id. El ejemplo es el siguiente:


4. Cláusula ORDER BY: clasificación múltiple

Los datos en la tabla de usuarios primero se ordenan en orden descendente según el campo de estado y luego en orden ascendente según el orden alfabético del nombre de usuario. El ejemplo es el siguiente:


3.10 Función SQL CONTAR(*)

1. gramática

La función COUNT(*) se utiliza para devolver el número total de elementos de datos en los resultados de la consulta. El formato de sintaxis es el siguiente:


2. Ejemplo de CONTAR(*)

Consulta el número total de elementos de datos con estado 0 en la tabla de usuarios:


3. Utilice AS para establecer alias para columnas

Si desea establecer un alias para el nombre de la columna consultada, puede utilizar la palabra clave AS. El ejemplo es el siguiente:


Operar MySQL en el proyecto.

4.1 Pasos para operar la base de datos en el proyecto

①Instale el módulo de terceros (mysql) que opera la base de datos MySQL

②Conéctese a la base de datos MySQL a través del módulo mysql

③Ejecutar sentencias SQL a través del módulo mysql

4.2 Instalar y configurar el módulo mysql

1. Instale el módulo mysql

El módulo mysql es un módulo de terceros alojado en npm. Proporciona la capacidad de conectar y operar bases de datos MySQL en proyectos Node.js.

Si desea usarlo en su proyecto, primero debe ejecutar el siguiente comando para instalar mysql como un paquete de dependencia del proyecto:

npm install mysql
2. Configurar el módulo mysql

Antes de utilizar el módulo mysql para operar la base de datos MySQL, primero debe configurar el módulo mysql según sea necesario. Los pasos principales de configuración son los siguientes:


3. Pruebe si el módulo mysql puede funcionar normalmente

Llame a la función db.query (), especifique la instrucción SQL que se ejecutará y obtenga el resultado de la ejecución a través de la función de devolución de llamada:


4.3 Utilice el módulo mysql para operar la base de datos MySQL

1. Consultar datos

Consulta todos los datos en la tabla de usuarios:


2. Insertar datos

Agregue nuevos datos a la tabla de usuarios, donde el nombre de usuario es Spider-Man y la contraseña es pcc321. El código de muestra es el siguiente:


3. Manera conveniente de insertar datos

Al agregar datos a la tabla, si cada atributo del objeto de datos corresponde a un campo de la tabla de datos, puede insertar datos rápidamente de las siguientes maneras:


4. Actualizar datos

Puede actualizar los datos de la tabla de las siguientes maneras:


5. Manera conveniente de actualizar datos

Al actualizar los datos de la tabla, si cada atributo del objeto de datos corresponde a un campo de la tabla de datos, puede actualizar rápidamente los datos de la tabla de las siguientes maneras:


6. Eliminar datos

Al eliminar datos, se recomienda eliminar los datos correspondientes en función de un identificador único como id. Los ejemplos son los siguientes:


7. Marcar para eliminar

El uso de la declaración DELETE en realidad eliminará los datos de la tabla. Para estar seguro, se recomienda utilizar la eliminación de marcas para simular la acción de eliminación.

La llamada eliminación de marca consiste en establecer un campo de estado similar al estado en la tabla para marcar si el dato actual se ha eliminado.

Cuando el usuario realiza la acción de eliminación, no ejecutamos la instrucción DELETE para eliminar los datos, sino que ejecutamos la instrucción ACTUALIZAR para marcar el campo de estado correspondiente a estos datos como eliminado.


Autenticación de identidad para front-end y back-end

5.1 modelo de desarrollo web

Actualmente existen dos modelos principales de desarrollo web, a saber:

①Modelo de desarrollo web tradicional basado en renderizado del lado del servidor

②Nuevo modelo de desarrollo web basado en la separación de front-end y back-end

1. Modelo de desarrollo web de renderizado del lado del servidor

El concepto de representación del lado del servidor: la página HTML enviada por el servidor al cliente se genera dinámicamente mediante la concatenación de cadenas en el servidor. Por lo tanto, el cliente no necesita utilizar tecnologías como Ajax para solicitar datos de página adicionales. El ejemplo de código es el siguiente:


2. Ventajas y desventajas del renderizado del lado del servidor

ventaja:

① La parte delantera lleva menos tiempo. Debido a que el lado del servidor es responsable de generar contenido HTML dinámicamente, el navegador solo necesita representar la página directamente. Especialmente la versión móvil ahorra más energía.

② Propicio para el SEO. Debido a que el servidor responde al contenido completo de la página HTML, es más fácil para los rastreadores rastrear y obtener información, lo que favorece el SEO.

defecto:

① Ocupa recursos del lado del servidor. Es decir, el servidor completa el empalme del contenido de la página HTML y, si hay muchas solicitudes, ejercerá una cierta presión de acceso sobre el servidor.

② No favorece la separación del front-end y el back-end y la eficiencia del desarrollo es baja. El uso de la representación del lado del servidor hace que sea imposible llevar a cabo la división del trabajo y la cooperación, especialmente para proyectos con alta complejidad frontal, lo que no favorece el desarrollo eficiente del proyecto.

3. Modelo de desarrollo web con separación de front-end y back-end

El concepto de separación de front-end y back-end: el modelo de desarrollo de separación de front-end y back-end se basa en la aplicación extensiva de la tecnología Ajax . En resumen, el modelo de desarrollo web en el que el front-end y el back-end están separados es un modelo de desarrollo en el que el back-end solo es responsable de proporcionar interfaces API , y el front-end usa Ajax para llamar a la interfaz .

4. Ventajas y desventajas de la separación de front-end y back-end

ventaja:

① **Buena experiencia de desarrollo. ** El front-end se centra en el desarrollo de páginas de interfaz de usuario, el back-end se centra en el desarrollo de API y el front-end tiene más opciones.

② **Buena experiencia de usuario. **La amplia aplicación de la tecnología Ajax ha mejorado enormemente la experiencia del usuario y puede lograr fácilmente una actualización parcial de la página.

③ **Reduce la presión de renderizado en el lado del servidor. **Porque la página se genera finalmente en el navegador de cada usuario.

defecto:

No favorece el SEO. ** Debido a que la página HTML completa debe empalmarse dinámicamente en el cliente, el rastreador no puede rastrear la información efectiva de la página. (Solución: ¡el uso de la tecnología SSR (representación del lado del servidor) de marcos front-end como Vue y React puede resolver muy bien los problemas de SEO!)

5. Cómo elegir un modelo de desarrollo web

Elegir a ciegas qué modelo de desarrollo utilizar sin hablar de escenarios empresariales es una medida deshonesta.

lPor ejemplo, un sitio web de nivel empresarial cuya función principal es mostrar sin interacciones complejas y requiere un buen SEO, entonces necesitamos utilizar la representación del lado del servidor;

l De manera similar a los proyectos de gestión de back-end, que son altamente interactivos y no necesitan considerar SEO, entonces puede usar el modelo de desarrollo que separa el front-end y el back-end.

Además, el modelo de desarrollo específico que se utilizará no es absoluto. Para tener en cuenta tanto la velocidad de renderizado de la página de inicio como la eficiencia del desarrollo de la separación front-end y back-end , algunos sitios web adoptan un modelo de desarrollo de primero. Representación del lado del servidor de pantalla + otras páginas con separación de front-end y back-end.

5.2 Autenticación de identidad

1. ¿Qué es la autenticación de identidad?

La autenticación de identidad (Autenticación), también conocida como "verificación de identidad" y "autenticación", se refiere a completar la confirmación de la identidad del usuario a través de ciertos medios .

  • La autenticación de identidad se puede ver en todas partes de la vida diaria, como: verificación de billetes de tren de alta velocidad, desbloqueo de contraseñas de teléfonos móviles o huellas dactilares, contraseñas de pago de Alipay o WeChat, etc.
  • En el desarrollo web, la autenticación de la identidad del usuario también está involucrada, como: inicio de sesión con código de verificación de teléfono móvil , inicio de sesión con contraseña de correo electrónico , inicio de sesión con código QR , etc. para los principales sitios web.
2. Por qué es necesaria la autenticación de identidad

El propósito de la autenticación de identidad es confirmar que el usuario que actualmente reclama una determinada identidad es de hecho el usuario reclamado . Por ejemplo, si vas al mensajero a recoger el envío urgente, ¿cómo demuestras que el envío urgente es tuyo?

En el desarrollo de proyectos de Internet, cómo autenticar la identidad de los usuarios es un tema que merece un debate en profundidad. Por ejemplo, ¿cómo podemos asegurarnos de que el sitio web no muestre por error "el monto del depósito de Jack Ma" en la "cuenta de Ma Huateng"?

3. Autenticación de identidad en diferentes modos de desarrollo.

Para los dos modos de desarrollo de renderizado del lado del servidor y separación de front-end y back-end, existen diferentes esquemas de autenticación:

① Se recomienda utilizar el mecanismo de autenticación de sesión para la representación del lado del servidor.

② Se recomienda utilizar el mecanismo de autenticación JWT para la separación de front-end y back-end.

5.3 Mecanismo de autenticación de sesión

1. Naturaleza sin estado del protocolo HTTP

Comprender la naturaleza sin estado del protocolo HTTP es un requisito previo necesario para aprender más sobre el mecanismo de autenticación de sesión.

La naturaleza sin estado del protocolo HTTP significa que cada solicitud HTTP del cliente es independiente , no existe una relación directa entre múltiples solicitudes consecutivas y el servidor no retendrá activamente el estado de cada solicitud HTTP .

Por favor agregue la descripción de la imagen.

2. Cómo superar las limitaciones sin estado de HTTP

Para los supermercados, para facilitar que el cajero ofrezca descuentos a los usuarios VIP durante la liquidación, el supermercado puede emitir tarjetas de membresía a cada usuario VIP.

Por favor agregue la descripción de la imagen.

Nota: La terminología profesional para la autenticación de identidad de la tarjeta de membresía en el desarrollo web es Cookie .

3. ¿Qué son las cookies?

Una cookie es una cadena de no más de 4 KB que se almacena en el navegador del usuario . Consta de un nombre (Nombre), un valor (Valor) y varios otros atributos opcionales que se utilizan para controlar el período de validez, la seguridad y el alcance de uso de las cookies.

Las cookies bajo diferentes nombres de dominio son independientes. Cada vez que el cliente inicia una solicitud, todas las cookies vigentes bajo el nombre de dominio actual se enviarán automáticamente al servidor.

Varias características principales de las cookies:

①Enviar automáticamente

②El nombre de dominio es independiente

③Límite de tiempo de vencimiento

④ Límite de 4 KB

4. El papel de las cookies en la autenticación de identidad

Cuando el cliente solicita al servidor por primera vez, el servidor envía una cookie de autenticación de identidad al cliente en forma de encabezado de respuesta y el cliente guarda automáticamente la cookie en el navegador.

Posteriormente, cada vez que el navegador del cliente solicita al servidor, el navegador enviará automáticamente la cookie relacionada con la autenticación de identidad al servidor en forma de encabezado de solicitud , y el servidor puede verificar la identidad del cliente.
Por favor agregue la descripción de la imagen.

5. Las cookies no son seguras

Dado que las cookies se almacenan en el navegador y el navegador también proporciona una API para leer y escribir cookies , las cookies se falsifican fácilmente y no son seguras. Por tanto, no se recomienda que el servidor envíe datos privados importantes al navegador en forma de cookies.

Por favor agregue la descripción de la imagen.

Nota: ¡Nunca utilice cookies para almacenar datos importantes y privados ! Por ejemplo, la información de identidad del usuario, contraseña, etc.

6. Mejorar la seguridad de la autenticación de identidad.

Para evitar que los clientes falsifiquen tarjetas de membresía, el cajero puede realizar la autenticación de la tarjeta en la caja registradora después de recibir la tarjeta de membresía presentada por el cliente . Sólo se pueden utilizar normalmente las tarjetas de membresía cuya existencia haya sido confirmada por la caja registradora.

Por favor agregue la descripción de la imagen.

Este concepto de diseño de " autenticación de tarjeta de membresía + tarjeta de crédito" es la esencia del mecanismo de autenticación de sesión.

7. Cómo funciona la sesión

Por favor agregue la descripción de la imagen.

5.4 Uso de la autenticación de sesión en Express

1. Instalar middleware de sesión rápida

En el proyecto Express, solo necesita instalar el middleware de sesión rápida para usar la autenticación de sesión en el proyecto:

npm install express-session
2. Configurar el middleware de sesión rápida

Una vez que el middleware de sesión rápida se haya instalado correctamente, debe registrar el middleware de sesión a través de app.use(). El código de muestra es el siguiente:


3. Almacenar datos en la sesión.

Una vez configurado correctamente el middleware de sesión rápida, se puede acceder al objeto de sesión y utilizarlo a través de req.session para almacenar la información clave del usuario:


4. Obtener datos de la sesión

Puede obtener directamente los datos almacenados previamente del objeto req.session . El código de muestra es el siguiente:


5. Borrar sesión

Llame a la función req.session.destroy() para borrar la información de la sesión guardada por el servidor.


5.5 Mecanismo de autenticación JWT

1. Comprenda las limitaciones de la autenticación de sesión

El mecanismo de autenticación de sesión debe implementarse con Cookie. Dado que las cookies no admiten el acceso entre dominios de forma predeterminada, cuando se trata de solicitudes de front-end entre dominios a interfaces de back-end, se requiere mucha configuración adicional para lograr la autenticación de sesión entre dominios.

Aviso:

  • Cuando el front-end solicita la interfaz de back-end y no hay problemas entre dominios , se recomienda utilizar el mecanismo de autenticación de identidad de sesión.
  • Cuando el front-end necesita solicitar la interfaz de back-end entre dominios, no se recomienda utilizar el mecanismo de autenticación de sesión y se recomienda utilizar el mecanismo de autenticación JWT.
2. ¿Qué es JWT?

JWT (nombre completo en inglés: JSON Web Token) es actualmente la solución de autenticación entre dominios más popular .

3. Cómo funciona JWT

Por favor agregue la descripción de la imagen.

Resumen: la información del usuario se almacena en el navegador del cliente en forma de cadena de token. El servidor autentica la identidad del usuario restaurando la cadena del token.

4. Componentes de JWT

JWT generalmente consta de tres partes: encabezado, carga útil y firma.

Los tres están separados por "." en inglés y el formato es el siguiente:

Header.Payload.Signature

El siguiente es un ejemplo de una cadena JWT:


5. ¿Qué representan las tres partes de JWT?

Los tres componentes de JWT, de adelante hacia atrás, son Encabezado, Carga útil y Firma.

en:

  • La parte de carga útil es la información real del usuario , que es una cadena generada después de cifrar la información del usuario.
  • El encabezado y la firma son partes relacionadas con la seguridad , solo para garantizar la seguridad del token.

Por favor agregue la descripción de la imagen.

6. Cómo utilizar JWT

Después de que el cliente recibe el JWT devuelto por el servidor, generalmente lo almacena en localStorage o sessionStorage.

Después de eso, cada vez que el cliente se comunica con el servidor, debe traer esta cadena JWT para la autenticación de identidad. El enfoque recomendado es colocar el JWT en el campo Autorización del encabezado de solicitud HTTP , en el siguiente formato:


5.6 Usando JWT con Express

1. Instale paquetes relacionados con JWT

Ejecute el siguiente comando para instalar los siguientes dos paquetes relacionados con JWT:

npm install jsonwebtoken express-jwt

en:

  • jsonwebtoken se utiliza para generar una cadena JWT
  • express-jwt se utiliza para analizar y restaurar cadenas JWT en objetos JSON
2. Importar paquetes relacionados con JWT

Utilice la función require() para importar los dos paquetes relacionados con JWT:


3. Definir clave secreta

Para garantizar la seguridad de la cadena JWT y evitar que otros la descifren durante la transmisión de la red, debemos definir específicamente una clave secreta para el cifrado y descifrado :

①Al generar una cadena JWT, debe utilizar la clave secreta para cifrar la información del usuario y, finalmente, obtener la cadena JWT cifrada.

②Al analizar y restaurar la cadena JWT en un objeto JSON, se debe utilizar la clave secreta para descifrar

//3.secret 密钥的本质:就是一个字符串
const secretKey = '123445'
4. Genere ** cadena JWT después de iniciar sesión correctamente

Llame al método sign() proporcionado por el paquete jsonwebtoken para cifrar la información del usuario en una cadena JWT y responder al cliente:


5. Restaurar la cadena JWT al objeto JSON

Cada vez que el cliente accede a esas interfaces autorizadas, debe enviar activamente la cadena de token al servidor para la autenticación de identidad a través del campo Autorización en el encabezado de la solicitud .

En este momento, el servidor puede analizar y restaurar automáticamente el token enviado por el cliente en un objeto JSON a través del middleware **express-** jwt :


6. Utilice req.user para obtener información del usuario.

Una vez que el middleware express-jwt se haya configurado correctamente, puede utilizar el objeto req.user en esas interfaces autorizadas para acceder a la información del usuario analizada desde la cadena JWT. El código de muestra es el siguiente:


7. Errores de captura generados después de no poder analizar JWT

Cuando se utiliza express-jwt para analizar la cadena Token, si la cadena Token enviada por el cliente está caducada o es ilegal , se producirá un error de análisis , lo que afectará el funcionamiento normal del proyecto. Podemos capturar este error y realizar el procesamiento relacionado a través del middleware de errores de Express.El código de muestra es el siguiente:


Titular

Proyecto API de backend para eventos grandes; consulte https://www.showdoc.cc/escook?page_id=3707158761215217 para obtener la documentación de la interfaz API

1. Inicialización

1.1 Crear proyecto

  1. Cree una nueva api_servercarpeta como directorio raíz del proyecto y ejecute el siguiente comando en el directorio raíz del proyecto para inicializar el archivo de configuración de administración de paquetes:
npm init -y
  1. Ejecute el siguiente comando para instalar una versión específica express:
npm i [email protected]
  1. Cree un nuevo archivo de entrada en el directorio raíz del proyecto app.jscomo archivo de entrada para todo el proyecto e inicialice el siguiente código:
// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()

// write your code here...

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

1.2 Configurar cors entre dominios

  1. Ejecute el siguiente comando para instalar corsel middleware:
npm i [email protected]
  1. app.jsImportar y configurar corsmiddleware en :
// 导入 cors 中间件
const cors = require('cors')
// 将 cors 注册为全局中间件
app.use(cors())

1.3 Configurar el middleware para analizar datos del formulario

  1. Utilice el siguiente código para configurar application/x-www-form-urlencodedel middleware que analiza los datos del formulario en el formato:
app.use(express.urlencoded({
    
     extended: false }))

1.4 Inicializar carpetas relacionadas con el enrutamiento

  1. En el directorio raíz del proyecto, cree una nueva routercarpeta para almacenar todos 路由los módulos .

    En el módulo de enrutamiento, solo se almacena la relación de mapeo entre la solicitud del cliente y la función de procesamiento.

  2. En el directorio raíz del proyecto, cree una nueva router_handlercarpeta para almacenar todos路由处理函数模块

    El módulo de función de procesamiento de enrutamiento es específicamente responsable de almacenar las funciones de procesamiento correspondientes a cada ruta.

1.5 Inicializar el módulo de enrutamiento de usuarios

  1. En routerla carpeta, cree un nuevo user.jsarchivo como módulo de enrutamiento del usuario y el código de inicialización es el siguiente:
const express = require('express')
// 创建路由对象
const router = express.Router()

// 注册新用户
router.post('/reguser', (req, res) => {
    
    
  res.send('reguser OK')
})

// 登录
router.post('/login', (req, res) => {
    
    
  res.send('login OK')
})

// 将路由对象共享出去
module.exports = router
  1. En app.js, importar y utilizar 用户路由模块:
// 导入并注册用户路由模块
const userRouter = require('./router/user')
app.use('/api', userRouter)

1.6 Extraer las funciones de procesamiento en el módulo de enrutamiento de usuarios

Finalidad: Para asegurar 路由模块la pureza de , se debe extraer todo al 路由处理函数correspondiente路由处理函数模块

  1. En /router_handler/user.js, utilice exportsobjetos para compartir los dos siguientes externamente 路由处理函数:
/
 * 在这里定义和用户相关的路由处理函数,供 /router/user.js 模块进行调用
 */

// 注册用户的处理函数
exports.regUser = (req, res) => {
    
    
  res.send('reguser OK')
}

// 登录的处理函数
exports.login = (req, res) => {
    
    
  res.send('login OK')
}
  1. Modifique /router/user.jsel código a la siguiente estructura:
const express = require('express')
const router = express.Router()

// 导入用户路由处理函数模块
const userHandler = require('../router_handler/user')

// 注册新用户
router.post('/reguser', userHandler.regUser)
// 登录
router.post('/login', userHandler.login)

module.exports = router

2. Inicia sesión y regístrate

2.1 Crear una nueva tabla ev_users

  1. En my_db_01la base de datos, cree una nueva ev_userstabla de la siguiente manera:
    [Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente (img-aPqzgzHF-1675261701055)(…/ %25E6%2595%2599%25E7% 25A8%258B/2022%25E6%259C%2580%25E6%2596%25B0%25E7%2589%2588%25E9%25BB%2591%25E9%25A9%25AC%25E7%25A8%25 8B %25E5%25BA%258F%25E5 % 2591%2598%25E5%2589%258D%25E7%25AB%25AF%25E5%25AD%25A6%25E4%25B9%25A0%25E8%25B7%25AF%25E7%25BA%25BF%25E5 %259B%25BE/3.%2520 %25E7%25AC%25AC%25E4%25B8%2589%25E9%2598%25B6%25E6%25AE%25B5%2520Vue%2520%25E5%25BC%2580%25E5%258F%2591/ 1.Node.js%25E9%259B %25B6%25E5%259F%25BA%25E7%25A1%2580%25E5%2585%25A5%25E9%2597%25A8%25E6%2595%2599%25E7%25A8%258B/nodo. js%25E2%2580%2594%25E8 %25B5%2584%25E6%2596%2599/day8/ppt/images/1.jpg)]

2.2 Instalar y configurar el módulo mysql

En el proyecto de interfaz API, debe instalar y configurar mysqleste módulo de terceros para conectar y operar la base de datos MySQL.

  1. Ejecute el siguiente comando para instalar mysqlel módulo:
npm i [email protected]
  1. Cree un nuevo archivo en el directorio raíz del proyecto /db/index.jsy cree un objeto de conexión de base de datos en este módulo personalizado:
// 导入 mysql 模块
const mysql = require('mysql')

// 创建数据库连接对象
const db = mysql.createPool({
    
    
  host: '127.0.0.1',
  user: 'root',
  password: 'admin123',
  database: 'my_db_01',
})

// 向外共享 db 数据库连接对象
module.exports = db

2.3 Registro

2.3.0 Pasos de implementación

  1. Comprobar si los datos del formulario son legales
  2. Comprueba si el nombre de usuario está ocupado
  3. Cifrar contraseñas
  4. Insertar nuevo usuario

2.3.1 Comprobar si los datos del formulario son legales

  1. Determinar si el nombre de usuario y la contraseña están vacíos
// 接收表单数据
const userinfo = req.body
// 判断数据是否合法
if (!userinfo.username || !userinfo.password) {
    
    
  return res.send({
    
     status: 1, message: '用户名或密码不能为空!' })
}

2.3.2 Detectar si el nombre de usuario está ocupado

  1. Importe el módulo de operación de la base de datos:
const db = require('../db/index')
  1. Definir declaración SQL:
const sql = `select * from ev_users where username=?`
  1. Ejecute la declaración SQL y determine si el nombre de usuario está ocupado según los resultados:
db.query(sql, [userinfo.username], function (err, results) {
    
    
  // 执行 SQL 语句失败
  if (err) {
    
    
    return res.send({
    
     status: 1, message: err.message })
  }
  // 用户名被占用
  if (results.length > 0) {
    
    
    return res.send({
    
     status: 1, message: '用户名被占用,请更换其他用户名!' })
  }
  // TODO: 用户名可用,继续后续流程...
})

2.3.3 Cifrar contraseñas

Para garantizar la seguridad de las contraseñas, no se recomienda 明文guardar las contraseñas de los usuarios en la base de datos en forma de加密存储


En el proyecto actual, utilizar el método bcryptjspara cifrar contraseñas de usuario tiene las siguientes ventajas:

  • La contraseña cifrada no se puede descifrar a la inversa
  • La misma contraseña en texto plano se cifra varias veces y los resultados del cifrado obtenidos son diferentes, lo que garantiza la seguridad.

  1. Ejecute el siguiente comando para instalar la versión especificada bcryptjs:
npm i [email protected]
  1. En /router_handler/user.js, importar bcryptjs:
const bcrypt = require('bcryptjs')
  1. En la función de procesamiento del usuario registrado, después de confirmar que el nombre de usuario está disponible, llame bcrypt.hashSync(明文密码, 随机盐的长度)al método para cifrar la contraseña del usuario:
// 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
userinfo.password = bcrypt.hashSync(userinfo.password, 10)

2.3.4 Insertar nuevo usuario

  1. Defina la declaración SQL para insertar usuarios:
const sql = 'insert into ev_users set ?'
  1. Llame db.query()para ejecutar la declaración SQL e insertar un nuevo usuario:
db.query(sql, {
    
     username: userinfo.username, password: userinfo.password }, function (err, results) {
    
    
  // 执行 SQL 语句失败
  if (err) return res.send({
    
     status: 1, message: err.message })
  // SQL 语句执行成功,但影响行数不为 1
  if (results.affectedRows !== 1) {
    
    
    return res.send({
    
     status: 1, message: '注册用户失败,请稍后再试!' })
  }
  // 注册成功
  res.send({
    
     status: 0, message: '注册成功!' })
})

2.4 Optimizar el código res.send()

En la función de procesamiento, debe llamar al resultado de res.send()responder al cliente varias veces. Para simplificar el código, puede encapsular manualmente una función res.cc ()处理失败

  1. En app.js, antes de todas las rutas, declara un middleware global y monta una res.cc()función para el objeto res:
// 响应数据的中间件
app.use(function (req, res, next) {
    
    
  // status = 0 为成功; status = 1 为失败; 默认将 status 的值设置为 1,方便处理失败的情况
  res.cc = function (err, status = 1) {
    
    
    res.send({
    
    
      // 状态
      status,
      // 状态描述,判断 err 是 错误对象 还是 字符串
      message: err instanceof Error ? err.message : err,
    })
  }
  next()
})

2.5 Optimizar la validación de datos del formulario

El principio de la verificación de formularios: la verificación del front-end es complementaria y la verificación del back-end es la principal. El back-end nunca debe creer nada de lo enviado por el front-end.

En el desarrollo real, tanto el front-end como el back-end necesitan verificar la legalidad de los datos del formulario. Además, el back-end, como última puerta para la verificación de la legalidad de los datos, juega un papel vital en la interceptación de datos ilegales.

Usar simplemente if...else...el formulario para verificar la legalidad de los datos es ineficiente, tiene una alta tasa de error y tiene poca capacidad de mantenimiento. Por lo tanto, se recomienda utilizar módulos de verificación de datos de terceros para reducir las tasas de error, mejorar la eficiencia y la capacidad de mantenimiento de la verificación y permitir que los programadores de back-end se concentren más en el procesamiento de la lógica empresarial central.

  1. Instale @hapi/joiel paquete y defina reglas de validación para cada elemento de datos incluido en el formulario:
npm install @hapi/[email protected]
  1. Instale @escook/express-joimiddleware para implementar la verificación automática de los datos del formulario:
npm i @escook/express-joi
  1. Cree un nuevo /schema/user.jsmódulo de reglas de verificación de información de usuario e inicialice el código de la siguiente manera:
const joi = require('@hapi/joi')

/
 * string() 值必须是字符串
 * alphanum() 值只能是包含 a-zA-Z0-9 的字符串
 * min(length) 最小长度
 * max(length) 最大长度
 * required() 值是必填项,不能为 undefined
 * pattern(正则表达式) 值必须符合正则表达式的规则
 */

// 用户名的验证规则
const username = joi.string().alphanum().min(1).max(10).required()
// 密码的验证规则
const password = joi
  .string()
  .pattern(/^[\S]{6,12}$/)
  .required()

// 注册和登录表单的验证规则对象
exports.reg_login_schema = {
    
    
  // 表示需要对 req.body 中的数据进行验证
  body: {
    
    
    username,
    password,
  },
}
  1. El /router/user.jscódigo modificado es el siguiente:
const express = require('express')
const router = express.Router()

// 导入用户路由处理函数模块
const userHandler = require('../router_handler/user')

// 1. 导入验证表单数据的中间件
const expressJoi = require('@escook/express-joi')
// 2. 导入需要的验证规则对象
const {
    
     reg_login_schema } = require('../schema/user')

// 注册新用户
// 3. 在注册新用户的路由中,声明局部中间件,对当前请求中携带的数据进行验证
// 3.1 数据验证通过后,会把这次请求流转给后面的路由处理函数
// 3.2 数据验证失败后,终止后续代码的执行,并抛出一个全局的 Error 错误,进入全局错误级别中间件中进行处理
router.post('/reguser', expressJoi(reg_login_schema), userHandler.regUser)
// 登录
router.post('/login', userHandler.login)

module.exports = router
  1. En app.jsel middleware de nivel de error global de , capture el error de falla de verificación y responda al cliente con el resultado de la falla de verificación:
const joi = require('@hapi/joi')

// 错误中间件
app.use(function (err, req, res, next) {
    
    
  // 数据验证失败
  if (err instanceof joi.ValidationError) return res.cc(err)
  // 未知错误
  res.cc(err)
})

2.6 Iniciar sesión

2.6.0 Pasos de implementación

  1. Comprobar si los datos del formulario son legales
  2. Consultar datos de usuario según el nombre de usuario.
  3. Determinar si la contraseña ingresada por el usuario es correcta
  4. Generar cadena de token JWT

2.6.1 Comprobar si los datos del formulario de inicio de sesión son legales

  1. Modifique el código de ruta de la siguiente manera /router/user.js:登录
// 登录的路由
router.post('/login', expressJoi(reg_login_schema), userHandler.login)

2.6.2 Consultar datos de usuario según el nombre de usuario

  1. Recibir datos del formulario:
const userinfo = req.body
  1. Definir declaración SQL:
const sql = `select * from ev_users where username=?`
  1. Ejecute sentencias SQL para consultar datos del usuario:
db.query(sql, userinfo.username, function (err, results) {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)
  // 执行 SQL 语句成功,但是查询到数据条数不等于 1
  if (results.length !== 1) return res.cc('登录失败!')
  // TODO:判断用户输入的登录密码是否和数据库中的密码一致
})

2.6.3 Determinar si la contraseña ingresada por el usuario es correcta

Idea de implementación central: llame bcrypt.compareSync(用户提交的密码, 数据库中的密码)al método para comparar si la contraseña es consistente

El valor de retorno es un valor booleano (verdadero es consistente, falso es inconsistente)

El código de implementación específico es el siguiente:

// 拿着用户输入的密码,和数据库中存储的密码进行对比
const compareResult = bcrypt.compareSync(userinfo.password, results[0].password)

// 如果对比的结果等于 false, 则证明用户输入的密码错误
if (!compareResult) {
    
    
  return res.cc('登录失败!')
}

// TODO:登录成功,生成 Token 字符串

2.6.4 Generar cadena de token JWT

Nota principal: al generar la cadena Token, asegúrese de eliminar los valores de contraseña y avatar.

  1. 密码Elimine rápidamente los valores de y a través de la sintaxis avanzada de ES6 头像:
// 剔除完毕之后,user 中只保留了用户的 id, username, nickname, email 这四个属性的值
const user = {
    
     ...results[0], password: '', user_pic: '' }
  1. Ejecute el siguiente comando para instalar el paquete que genera la cadena Token:
npm i [email protected]
  1. En /router_handler/user.jsel área del encabezado del módulo, importe jsonwebtokenel paquete:
// 用这个包来生成 Token 字符串
const jwt = require('jsonwebtoken')
  1. Cree config.jsun archivo y comparta jwtSecretKeyla cadena del token de cifrado y restauración externamente:
module.exports = {
    
    
  jwtSecretKey: 'itheima No1. ^_^',
}
  1. Cifre el objeto de información del usuario en una cadena de token:
// 导入配置文件
const config = require('../config')

// 生成 Token 字符串
const tokenStr = jwt.sign(user, config.jwtSecretKey, {
    
    
  expiresIn: '10h', // token 有效期为 10 个小时
})
  1. Responda la cadena de token generada al cliente:
res.send({
    
    
  status: 0,
  message: '登录成功!',
  // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
  token: 'Bearer ' + tokenStr,
})

2.7 Configurar el middleware para analizar Token

  1. Ejecute el siguiente comando para instalar el middleware para analizar el Token:
npm i express-jwt@5.3.3
  1. Antes de registrar la ruta en app.js, configure el middleware que analiza el Token:
// 导入配置文件
const config = require('./config')

// 解析 token 的中间件
const expressJWT = require('express-jwt')

// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
app.use(expressJWT({
    
     secret: config.jwtSecretKey }).unless({
    
     path: [/^\/api\//] }))
  1. En , capture y maneje los errores después de que falla la autenticación del token app.js:错误级别中间件
// 错误中间件
app.use(function (err, req, res, next) {
    
    
  // 省略其它代码...

  // 捕获身份认证失败的错误
  if (err.name === 'UnauthorizedError') return res.cc('身份认证失败!')

  // 未知错误...
})

3. Centro personal

3.1 Obtener información básica de los usuarios

3.1.0 Pasos de implementación

  1. Inicializar módulo de enrutamiento
  2. Inicializar el módulo de función de procesamiento de ruta
  3. Obtener información básica del usuario.

3.1.1 Inicializar módulo de enrutamiento

  1. Cree /router/userinfo.jsun módulo de enrutamiento e inicialice la siguiente estructura de código:
// 导入 express
const express = require('express')
// 创建路由对象
const router = express.Router()

// 获取用户的基本信息
router.get('/userinfo', (req, res) => {
    
    
  res.send('ok')
})

// 向外共享路由对象
module.exports = router
  1. app.jsImporte y utilice el módulo de enrutamiento del centro personal en :
// 导入并使用用户信息路由模块
const userinfoRouter = require('./router/userinfo')
// 注意:以 /my 开头的接口,都是有权限的接口,需要进行 Token 身份认证
app.use('/my', userinfoRouter)

3.1.2 Inicializar el módulo de función de procesamiento de enrutamiento

  1. Cree /router_handler/userinfo.jsun módulo de función de procesamiento de enrutamiento e inicialice la siguiente estructura de código:
// 获取用户基本信息的处理函数
exports.getUserInfo = (req, res) => {
    
    
  res.send('ok')
}
  1. El /router/userinfo.jscódigo modificado es el siguiente:
const express = require('express')
const router = express.Router()

// 导入用户信息的处理函数模块
const userinfo_handler = require('../router_handler/userinfo')

// 获取用户的基本信息
router.get('/userinfo', userinfo_handler.getUserInfo)

module.exports = router

3.1.3 Obtener información básica de los usuarios

  1. Importe el módulo de operación de la base de datos en /router_handler/userinfo.jsel encabezado:
// 导入数据库操作模块
const db = require('../db/index')
  1. Definir declaración SQL:
// 根据用户的 id,查询用户的基本信息
// 注意:为了防止用户的密码泄露,需要排除 password 字段
const sql = `select id, username, nickname, email, user_pic from ev_users where id=?`
  1. Llamada db.query()para ejecutar una declaración SQL:
// 注意:req 对象上的 user 属性,是 Token 解析成功,express-jwt 中间件帮我们挂载上去的
db.query(sql, req.user.id, (err, results) => {
    
    
  // 1. 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 2. 执行 SQL 语句成功,但是查询到的数据条数不等于 1
  if (results.length !== 1) return res.cc('获取用户信息失败!')

  // 3. 将用户信息响应给客户端
  res.send({
    
    
    status: 0,
    message: '获取用户基本信息成功!',
    data: results[0],
  })
})

3.2 Actualizar la información básica del usuario

3.2.0 Pasos de implementación

  1. Definir funciones de enrutamiento y procesamiento.
  2. Validar datos del formulario
  3. Implementar la función de actualizar la información básica del usuario.

3.2.1 Definir funciones de enrutamiento y procesamiento

  1. En /router/userinfo.jsel módulo, agregue 更新用户基本信息una nueva ruta:
// 更新用户的基本信息
router.post('/userinfo', userinfo_handler.updateUserInfo)
  1. En /router_handler/userinfo.jsel módulo, defina y comparta 更新用户基本信息la función de procesamiento de rutas externamente:
// 更新用户基本信息的处理函数
exports.updateUserInfo = (req, res) => {
    
    
  res.send('ok')
}

3.2.2 Validar datos del formulario

  1. En /schema/user.jsel módulo de reglas de verificación, defina las reglas de verificación idde la siguiente manera:nicknameemail
// 定义 id, nickname, emial 的验证规则
const id = joi.number().integer().min(1).required()
const nickname = joi.string().required()
const email = joi.string().email().required()
  1. Y utilícelo exportspara compartir externamente de la siguiente manera 验证规则对象:
// 验证规则对象 - 更新用户基本信息
exports.update_userinfo_schema = {
    
    
  body: {
    
    
    id,
    nickname,
    email,
  },
}
  1. En /router/userinfo.jsel módulo importe el middleware que verifica la validez de los datos:
// 导入验证数据合法性的中间件
const expressJoi = require('@escook/express-joi')
  1. En /router/userinfo.jsel módulo, importe los objetos de reglas de validación requeridos:
// 导入需要的验证规则对象
const {
    
     update_userinfo_schema } = require('../schema/user')
  1. En /router/userinfo.jsel módulo, modifique 更新用户的基本信息el enrutamiento de la siguiente manera:
// 更新用户的基本信息
router.post('/userinfo', expressJoi(update_userinfo_schema), userinfo_handler.updateUserInfo)

3.2.3 Implementar la función de actualizar la información básica del usuario.

  1. Defina la declaración SQL que se ejecutará:
const sql = `update ev_users set ? where id=?`
  1. Llame db.query()para ejecutar la declaración SQL y pasar parámetros:
db.query(sql, [req.body, req.body.id], (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 执行 SQL 语句成功,但影响行数不为 1
  if (results.affectedRows !== 1) return res.cc('修改用户基本信息失败!')

  // 修改用户信息成功
  return res.cc('修改用户基本信息成功!', 0)
})

3.3 Restablecer contraseña

3.3.0 Pasos de implementación

  1. Definir funciones de enrutamiento y procesamiento.
  2. Validar datos del formulario
  3. Implementar la función de restablecer contraseña.

3.3.1 Definir funciones de enrutamiento y procesamiento

  1. En /router/userinfo.jsel módulo, agregue 重置密码una nueva ruta:
// 重置密码的路由
router.post('/updatepwd', userinfo_handler.updatePassword)
  1. En /router_handler/userinfo.jsel módulo, defina y comparta 重置密码la función de procesamiento de rutas externamente:
// 重置密码的处理函数
exports.updatePassword = (req, res) => {
    
    
  res.send('ok')
}

3.3.2 Validar datos del formulario

Idea central de verificación: la contraseña anterior y la nueva deben cumplir con las reglas de verificación de contraseña, ¡y la nueva contraseña no puede ser consistente con la contraseña anterior!

  1. En /schema/user.jsel módulo, utilice el uso exportscompartido externo de la siguiente manera 验证规则对象:
// 验证规则对象 - 重置密码
exports.update_password_schema = {
    
    
  body: {
    
    
    // 使用 password 这个规则,验证 req.body.oldPwd 的值
    oldPwd: password,
    // 使用 joi.not(joi.ref('oldPwd')).concat(password) 规则,验证 req.body.newPwd 的值
    // 解读:
    // 1. joi.ref('oldPwd') 表示 newPwd 的值必须和 oldPwd 的值保持一致
    // 2. joi.not(joi.ref('oldPwd')) 表示 newPwd 的值不能等于 oldPwd 的值
    // 3. .concat() 用于合并 joi.not(joi.ref('oldPwd')) 和 password 这两条验证规则
    newPwd: joi.not(joi.ref('oldPwd')).concat(password),
  },
}
  1. En /router/userinfo.jsel módulo, importe los objetos de reglas de validación requeridos:
// 导入需要的验证规则对象
const {
    
     update_userinfo_schema, update_password_schema } = require('../schema/user')
  1. Y en 重置密码的路由usa update_password_schemareglas para verificar los datos del formulario, el código de muestra es el siguiente:
router.post('/updatepwd', expressJoi(update_password_schema), userinfo_handler.updatePassword)

3.3.3 Implementar la función de restablecer contraseña

  1. Compruebe si el usuario existe según id:
// 定义根据 id 查询用户数据的 SQL 语句
const sql = `select * from ev_users where id=?`

// 执行 SQL 语句查询用户是否存在
db.query(sql, req.user.id, (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 检查指定 id 的用户是否存在
  if (results.length !== 1) return res.cc('用户不存在!')

  // TODO:判断提交的旧密码是否正确
})
  1. Determine si la contraseña anterior enviada es correcta:
// 在头部区域导入 bcryptjs 后,
// 即可使用 bcrypt.compareSync(提交的密码,数据库中的密码) 方法验证密码是否正确
// compareSync() 函数的返回值为布尔值,true 表示密码正确,false 表示密码错误
const bcrypt = require('bcryptjs')

// 判断提交的旧密码是否正确
const compareResult = bcrypt.compareSync(req.body.oldPwd, results[0].password)
if (!compareResult) return res.cc('原密码错误!')
  1. Después de cifrar la nueva contraseña bcrypt, actualícela en la base de datos:
// 定义更新用户密码的 SQL 语句
const sql = `update ev_users set password=? where id=?`

// 对新密码进行 bcrypt 加密处理
const newPwd = bcrypt.hashSync(req.body.newPwd, 10)

// 执行 SQL 语句,根据 id 更新用户的密码
db.query(sql, [newPwd, req.user.id], (err, results) => {
    
    
  // SQL 语句执行失败
  if (err) return res.cc(err)

  // SQL 语句执行成功,但是影响行数不等于 1
  if (results.affectedRows !== 1) return res.cc('更新密码失败!')

  // 更新密码成功
  res.cc('更新密码成功!', 0)
})

3.4 Actualizar avatar de usuario

3.4.0 Pasos de implementación

  1. Definir funciones de enrutamiento y procesamiento.
  2. Validar datos del formulario
  3. Implementar la función de actualización de avatares de usuarios.

3.4.1 Definir funciones de enrutamiento y procesamiento

  1. En /router/userinfo.jsel módulo, agregue 更新用户头像una nueva ruta:
// 更新用户头像的路由
router.post('/update/avatar', userinfo_handler.updateAvatar)
  1. En /router_handler/userinfo.jsel módulo, defina y comparta 更新用户头像la función de procesamiento de rutas externamente:
// 更新用户头像的处理函数
exports.updateAvatar = (req, res) => {
    
    
  res.send('ok')
}

3.4.2 Validar datos del formulario

  1. En /schema/user.jsel módulo de reglas de validación, avatarlas reglas de validación definidas son las siguientes:
// dataUri() 指的是如下格式的字符串数据:
// data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=
const avatar = joi.string().dataUri().required()
  1. Y utilícelo exportspara compartir externamente de la siguiente manera 验证规则对象:
// 验证规则对象 - 更新头像
exports.update_avatar_schema = {
    
    
  body: {
    
    
    avatar,
  },
}
  1. En /router/userinfo.jsel módulo, importe los objetos de reglas de validación requeridos:
const {
    
     update_avatar_schema } = require('../schema/user')
  1. En /router/userinfo.jsel módulo, modifique 更新用户头像el enrutamiento de la siguiente manera:
router.post('/update/avatar', expressJoi(update_avatar_schema), userinfo_handler.updateAvatar)

3.4.3 Implementar la función de actualizar avatares de usuarios.

  1. Defina la declaración SQL para actualizar el avatar del usuario:
const sql = 'update ev_users set user_pic=? where id=?'
  1. Llame db.query()para ejecutar la declaración SQL y actualizar el avatar del usuario correspondiente:
db.query(sql, [req.body.avatar, req.user.id], (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 执行 SQL 语句成功,但是影响行数不等于 1
  if (results.affectedRows !== 1) return res.cc('更新头像失败!')

  // 更新用户头像成功
  return res.cc('更新头像成功!', 0)
})

4. Gestión de clasificación de artículos.

4.1 Crear una nueva tabla ev_article_cate

4.1.1 Crear estructura de tabla

(La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente (img-nydYDiv0-1675261701055)(…/%25E6%2595%2599%25E7%25A8 %258B/2022%25E6% 259C%2580%25E6%2596%25B0%25E7%2589%2588%25E9%25BB%2591%25E9%25A9%25AC%25E7%25A8%258B%25E5%25BA%258F%25E5%259 1 %2598%25E5%2589 % 258D%25E7%25AB%25AF%25E5%25AD%25A6%25E4%25B9%25A0%25E8%25B7%25AF%25E7%25BA%25BF%25E5%259B%25BE/3.%2520% 25E7%25AC%25AC%25E4 %25B8%2589%25E9%2598%25B6%25E6%25AE%25B5%2520Vue%2520%25E5%25BC%2580%25E5%258F%2591/1.Node.js%25E9%259B% 25B6%25E5%259F%25BA %25E7%25A1%2580%25E5%2585%25A5%25E9%2597%25A8%25E6%2595%2599%25E7%25A8%258B/node.js%25E2%2580%2594%25E8% 25B5%2584%25E6%2596 %2599/day8/ppt/images/2.jpg)]

4.1.2 Agregar dos nuevos datos iniciales

(La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente (img-aQJqCGSl-1675261701056)(…/%25E6%2595%2599%25E7%25A8 %258B/2022%25E6% 259C%2580%25E6%2596%25B0%25E7%2589%2588%25E9%25BB%2591%25E9%25A9%25AC%25E7%25A8%258B%25E5%25BA%258F%25E5%259 1 %2598%25E5%2589 % 258D%25E7%25AB%25AF%25E5%25AD%25A6%25E4%25B9%25A0%25E8%25B7%25AF%25E7%25BA%25BF%25E5%259B%25BE/3.%2520% 25E7%25AC%25AC%25E4 %25B8%2589%25E9%2598%25B6%25E6%25AE%25B5%2520Vue%2520%25E5%25BC%2580%25E5%258F%2591/1.Node.js%25E9%259B% 25B6%25E5%259F%25BA %25E7%25A1%2580%25E5%2585%25A5%25E9%2597%25A8%25E6%2595%2599%25E7%25A8%258B/node.js%25E2%2580%2594%25E8% 25B5%2584%25E6%2596 %2599/day8/ppt/images/3.jpg)]

4.2 Obtener la lista de clasificación de artículos

4.2.0 Pasos de implementación

  1. Inicializar módulo de enrutamiento
  2. Inicializar el módulo de función de procesamiento de ruta
  3. Obtener datos de la lista de categorías de artículos

4.2.1 Inicializar módulo de enrutamiento

  1. Cree /router/artcate.jsun módulo de enrutamiento e inicialice la siguiente estructura de código:
// 导入 express
const express = require('express')
// 创建路由对象
const router = express.Router()

// 获取文章分类的列表数据
router.get('/cates', (req, res) => {
    
    
  res.send('ok')
})

// 向外共享路由对象
module.exports = router
  1. app.jsImporte y utilice el módulo de enrutamiento de clasificación de artículos en :
// 导入并使用文章分类路由模块
const artCateRouter = require('./router/artcate')
// 为文章分类的路由挂载统一的访问前缀 /my/article
app.use('/my/article', artCateRouter)

4.2.2 Inicializar el módulo de función de procesamiento de ruta

  1. Cree /router_handler/artcate.jsun módulo de función de procesamiento de enrutamiento e inicialice la siguiente estructura de código:
// 获取文章分类列表数据的处理函数
exports.getArticleCates = (req, res) => {
    
    
  res.send('ok')
}
  1. El /router/artcate.jscódigo modificado es el siguiente:
const express = require('express')
const router = express.Router()

// 导入文章分类的路由处理函数模块
const artcate_handler = require('../router_handler/artcate')

// 获取文章分类的列表数据
router.get('/cates', artcate_handler.getArticleCates)

module.exports = router

4.2.3 Obtener datos de la lista de clasificación de artículos

  1. Importe el módulo de operación de la base de datos en /router_handler/artcate.jsel encabezado:
// 导入数据库操作模块
const db = require('../db/index')
  1. Definir declaración SQL:
// 根据分类的状态,获取所有未被删除的分类列表数据
// is_delete 为 0 表示没有被 标记为删除 的数据
const sql = 'select * from ev_article_cate where is_delete=0 order by id asc'
  1. Llamada db.query()para ejecutar una declaración SQL:
db.query(sql, (err, results) => {
    
    
  // 1. 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 2. 执行 SQL 语句成功
  res.send({
    
    
    status: 0,
    message: '获取文章分类列表成功!',
    data: results,
  })
})

4.3 Agregar nuevas categorías de artículos

4.3.0 Pasos de implementación

  1. Definir funciones de enrutamiento y procesamiento.
  2. Validar datos del formulario
  3. Consultar si 分类名称y 分类别名está ocupado
  4. Implementar la función de agregar nuevas categorías de artículos.

4.3.1 Definir funciones de enrutamiento y procesamiento

  1. En /router/artcate.jsel módulo, agregue 新增文章分类una ruta para:
// 新增文章分类的路由
router.post('/addcates', artcate_handler.addArticleCates)
  1. En /router_handler/artcate.jsel módulo, defina y comparta 新增文章分类la función de procesamiento de rutas externamente:
// 新增文章分类的处理函数
exports.addArticleCates = (req, res) => {
    
    
  res.send('ok')
}

4.3.2 Validar datos del formulario

  1. Cree /schema/artcate.jsun módulo de validación de datos de clasificación de artículos y defina las siguientes reglas de validación:
// 导入定义验证规则的模块
const joi = require('@hapi/joi')

// 定义 分类名称 和 分类别名 的校验规则
const name = joi.string().required()
const alias = joi.string().alphanum().required()

// 校验规则对象 - 添加分类
exports.add_cate_schema = {
    
    
  body: {
    
    
    name,
    alias,
  },
}
  1. En /router/artcate.jsel módulo add_cate_schemavalidar los datos usando:
// 导入验证数据的中间件
const expressJoi = require('@escook/express-joi')
// 导入文章分类的验证模块
const {
    
     add_cate_schema } = require('../schema/artcate')

// 新增文章分类的路由
router.post('/addcates', expressJoi(add_cate_schema), artcate_handler.addArticleCates)

4.3.3 Consultar si el nombre de la categoría y el alias están ocupados

  1. Defina la declaración SQL para comprobar la duplicación:
// 定义查询 分类名称 与 分类别名 是否被占用的 SQL 语句
const sql = `select * from ev_article_cate where name=? or alias=?`
  1. Llame db.query()para realizar la operación de verificación de duplicados:
// 执行查重操作
db.query(sql, [req.body.name, req.body.alias], (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 判断 分类名称 和 分类别名 是否被占用
  if (results.length === 2) return res.cc('分类名称与别名被占用,请更换后重试!')
  // 分别判断 分类名称 和 分类别名 是否被占用
  if (results.length === 1 && results[0].name === req.body.name) return res.cc('分类名称被占用,请更换后重试!')
  if (results.length === 1 && results[0].alias === req.body.alias) return res.cc('分类别名被占用,请更换后重试!')

  // TODO:新增文章分类
})

4.3.4 Implementar la función de agregar nuevas categorías de artículos

  1. Declaración SQL para definir la nueva categoría de artículo:
const sql = `insert into ev_article_cate set ?`
  1. Llame para db.query()ejecutar la declaración SQL para agregar nuevas categorías de artículos:
db.query(sql, req.body, (err, results) => {
    
    
  // SQL 语句执行失败
  if (err) return res.cc(err)

  // SQL 语句执行成功,但是影响行数不等于 1
  if (results.affectedRows !== 1) return res.cc('新增文章分类失败!')

  // 新增文章分类成功
  res.cc('新增文章分类成功!', 0)
})

4.4 Eliminar categorías de artículos según la identificación

4.4.0 Pasos de implementación

  1. Definir funciones de enrutamiento y procesamiento.
  2. Validar datos del formulario
  3. Implementar la función de eliminar categorías de artículos.

4.4.1 Definir funciones de enrutamiento y procesamiento

  1. En /router/artcate.jsel módulo, agregue 删除文章分类una ruta para:
// 删除文章分类的路由
router.get('/deletecate/:id', artcate_handler.deleteCateById)
  1. En /router_handler/artcate.jsel módulo, defina y comparta 删除文章分类la función de procesamiento de rutas externamente:
// 删除文章分类的处理函数
exports.deleteCateById = (req, res) => {
    
    
  res.send('ok')
}

4.4.2 Validar datos del formulario

  1. En /schema/artcate.jsel módulo de reglas de validación, defina las reglas de validación para id de la siguiente manera:
// 定义 分类Id 的校验规则
const id = joi.number().integer().min(1).required()
  1. Y utilícelo exportspara compartir externamente de la siguiente manera 验证规则对象:
// 校验规则对象 - 删除分类
exports.delete_cate_schema = {
    
    
  params: {
    
    
    id,
  },
}
  1. En /router/artcate.jsel módulo, importe los objetos de reglas de validación necesarios y utilícelos en el enrutamiento:
// 导入删除分类的验证规则对象
const {
    
     delete_cate_schema } = require('../schema/artcate')

// 删除文章分类的路由
router.get('/deletecate/:id', expressJoi(delete_cate_schema), artcate_handler.deleteCateById)

4.4.3 Implementar la función de eliminar categorías de artículos.

  1. Defina la declaración SQL para eliminar categorías de artículos:
const sql = `update ev_article_cate set is_delete=1 where id=?`
  1. Llame db.query()para ejecutar la declaración SQL para eliminar la clasificación del artículo:
db.query(sql, req.params.id, (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // SQL 语句执行成功,但是影响行数不等于 1
  if (results.affectedRows !== 1) return res.cc('删除文章分类失败!')

  // 删除文章分类成功
  res.cc('删除文章分类成功!', 0)
})

4.5 Obtener datos de clasificación de artículos según Id.

4.5.0 Pasos de implementación

  1. Definir funciones de enrutamiento y procesamiento.
  2. Validar datos del formulario
  3. Implementar la función de obtención de clasificación de artículos.

4.5.1 Definir funciones de enrutamiento y procesamiento

  1. En /router/artcate.jsel módulo, agregue 根据 Id 获取文章分类una ruta para:
router.get('/cates/:id', artcate_handler.getArticleById)
  1. En /router_handler/artcate.jsel módulo, defina y comparta 根据 Id 获取文章分类la función de procesamiento de rutas externamente:
// 根据 Id 获取文章分类的处理函数
exports.getArticleById = (req, res) => {
    
    
  res.send('ok')
}

4.5.2 Validar datos del formulario

  1. En /schema/artcate.jsel módulo de reglas de validación, utilice el uso exportscompartido externo de la siguiente manera 验证规则对象:
// 校验规则对象 - 根据 Id 获取分类
exports.get_cate_schema = {
    
    
  params: {
    
    
    id,
  },
}
  1. En /router/artcate.jsel módulo, importe los objetos de reglas de validación necesarios y utilícelos en el enrutamiento:
// 导入根据 Id 获取分类的验证规则对象
const {
    
     get_cate_schema } = require('../schema/artcate')

// 根据 Id 获取文章分类的路由
router.get('/cates/:id', expressJoi(get_cate_schema), artcate_handler.getArticleById)

4.5.3 Implementar la función de obtención de clasificación de artículos.

  1. Defina la declaración SQL para obtener la clasificación del artículo según el Id:
const sql = `select * from ev_article_cate where id=?`
  1. Llamada db.query()para ejecutar una declaración SQL:
db.query(sql, req.params.id, (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // SQL 语句执行成功,但是没有查询到任何数据
  if (results.length !== 1) return res.cc('获取文章分类数据失败!')

  // 把数据响应给客户端
  res.send({
    
    
    status: 0,
    message: '获取文章分类数据成功!',
    data: results[0],
  })
})

4.6 Actualizar datos de clasificación de artículos según Id.

4.6.0 Pasos de implementación

  1. Definir funciones de enrutamiento y procesamiento.
  2. Validar datos del formulario
  3. Consultar si 分类名称y 分类别名está ocupado
  4. Implementar la función de actualización de la clasificación de artículos.

4.6.1 Definir funciones de enrutamiento y procesamiento

  1. En /router/artcate.jsel módulo, agregue 更新文章分类una ruta para:
// 更新文章分类的路由
router.post('/updatecate', artcate_handler.updateCateById)
  1. En /router_handler/artcate.jsel módulo, defina y comparta 更新文章分类la función de procesamiento de rutas externamente:
// 更新文章分类的处理函数
exports.updateCateById = (req, res) => {
    
    
  res.send('ok')
}

4.6.2 Validar datos del formulario

  1. En /schema/artcate.jsel módulo de reglas de validación, utilice el uso exportscompartido externo de la siguiente manera 验证规则对象:
// 校验规则对象 - 更新分类
exports.update_cate_schema = {
    
    
  body: {
    
    
    Id: id,
    name,
    alias,
  },
}
  1. En /router/artcate.jsel módulo, importe los objetos de reglas de validación necesarios y utilícelos en el enrutamiento:
// 导入更新文章分类的验证规则对象
const {
    
     update_cate_schema } = require('../schema/artcate')

// 更新文章分类的路由
router.post('/updatecate', expressJoi(update_cate_schema), artcate_handler.updateCateById)

4.5.4 Consultar si el nombre de la categoría y el alias están ocupados

  1. Defina la declaración SQL para comprobar la duplicación:
// 定义查询 分类名称 与 分类别名 是否被占用的 SQL 语句
const sql = `select * from ev_article_cate where Id<>? and (name=? or alias=?)`
  1. Llame db.query()para realizar la operación de verificación de duplicados:
// 执行查重操作
db.query(sql, [req.body.Id, req.body.name, req.body.alias], (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 判断 分类名称 和 分类别名 是否被占用
  if (results.length === 2) return res.cc('分类名称与别名被占用,请更换后重试!')
  if (results.length === 1 && results[0].name === req.body.name) return res.cc('分类名称被占用,请更换后重试!')
  if (results.length === 1 && results[0].alias === req.body.alias) return res.cc('分类别名被占用,请更换后重试!')

  // TODO:更新文章分类
})

4.5.5 Implementar la función de actualización de la clasificación de artículos.

  1. Defina la declaración SQL para actualizar la clasificación del artículo:
const sql = `update ev_article_cate set ? where Id=?`
  1. Llamada db.query()para ejecutar una declaración SQL:
db.query(sql, [req.body, req.body.Id], (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // SQL 语句执行成功,但是影响行数不等于 1
  if (results.affectedRows !== 1) return res.cc('更新文章分类失败!')

  // 更新文章分类成功
  res.cc('更新文章分类成功!', 0)
})

5. Gestión de artículos

5.1 Crear una nueva tabla ev_articles

(La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente (img-aYXbXiK2-1675261701056)(…/%25E6%2595%2599%25E7%25A8 %258B/2022%25E6% 259C%2580%25E6%2596%25B0%25E7%2589%2588%25E9%25BB%2591%25E9%25A9%25AC%25E7%25A8%258B%25E5%25BA%258F%25E5%259 1 %2598%25E5%2589 % 258D%25E7%25AB%25AF%25E5%25AD%25A6%25E4%25B9%25A0%25E8%25B7%25AF%25E7%25BA%25BF%25E5%259B%25BE/3.%2520% 25E7%25AC%25AC%25E4 %25B8%2589%25E9%2598%25B6%25E6%25AE%25B5%2520Vue%2520%25E5%25BC%2580%25E5%258F%2591/1.Node.js%25E9%259B% 25B6%25E5%259F%25BA %25E7%25A1%2580%25E5%2585%25A5%25E9%2597%25A8%25E6%2595%2599%25E7%25A8%258B/node.js%25E2%2580%2594%25E8% 25B5%2584%25E6%2596 %2599/day8/ppt/images/4.jpg)]

5.2 Publicar nuevos artículos

5.2.0 Pasos de implementación

  1. Inicializar módulo de enrutamiento
  2. Inicializar el módulo de función de procesamiento de ruta
  3. Utilice multer para analizar los datos del formulario
  4. Validar datos del formulario
  5. Implementar la función de publicar artículos.

5.2.1 Inicializar módulo de enrutamiento

  1. Cree /router/article.jsun módulo de enrutamiento e inicialice la siguiente estructura de código:
// 导入 express
const express = require('express')
// 创建路由对象
const router = express.Router()

// 发布新文章
router.post('/add', (req, res) => {
    
    
  res.send('ok')
})

// 向外共享路由对象
module.exports = router
  1. app.jsImporte y utilice el módulo de enrutamiento del artículo en :
// 导入并使用文章路由模块
const articleRouter = require('./router/article')
// 为文章的路由挂载统一的访问前缀 /my/article
app.use('/my/article', articleRouter)

5.2.2 Inicializar el módulo de función de procesamiento de enrutamiento

  1. Cree /router_handler/article.jsun módulo de función de procesamiento de enrutamiento e inicialice la siguiente estructura de código:
// 发布新文章的处理函数
exports.addArticle = (req, res) => {
    
    
  res.send('ok')
}
  1. El /router/article.jscódigo modificado es el siguiente:
const express = require('express')
const router = express.Router()

// 导入文章的路由处理函数模块
const article_handler = require('../router_handler/article')

// 发布新文章
router.post('/add', article_handler.addArticle)

module.exports = router

5.2.3 Utilice Multer para analizar los datos del formulario.

Nota: Los datos del cuerpo de la solicitud en formato express.urlencoded()no se pueden analizar mediante middleware .multipart/form-data

Para el proyecto actual, se recomienda utilizar multer para analizar multipart/form-datalos datos del formulario en formato. https://www.npmjs.com/package/multer

  1. Ejecute el siguiente comando de terminal para instalar en el proyecto multer:
npm i [email protected]
  1. /router_handler/article.jsImportar y configurar en módulo multer:
// 导入解析 formdata 格式表单数据的包
const multer = require('multer')
// 导入处理路径的核心模块
const path = require('path')

// 创建 multer 的实例对象,通过 dest 属性指定文件的存放路径
const upload = multer({
    
     dest: path.join(__dirname, '../uploads') })
  1. La 发布新文章ruta modificada es la siguiente:
// 发布新文章的路由
// upload.single() 是一个局部生效的中间件,用来解析 FormData 格式的表单数据
// 将文件类型的数据,解析并挂载到 req.file 属性中
// 将文本类型的数据,解析并挂载到 req.body 属性中
router.post('/add', upload.single('cover_img'), article_handler.addArticle)
  1. En la función de procesamiento /router_handler/article.jsdel módulo addArticle, multerimprima los datos analizados:
// 发布新文章的处理函数
exports.addArticle = (req, res) => {
    
    
  console.log(req.body) // 文本类型的数据
  console.log('--------分割线----------')
  console.log(req.file) // 文件类型的数据

  res.send('ok')
})

5.2.4 Validación de datos del formulario

Idea de implementación: verificar automáticamente los datos de texto en req.body a través de express-joi, verificar manualmente los datos del archivo en req.file a través del juicio if;

  1. Cree /schema/article.jsun módulo de reglas de validación e inicialice la siguiente estructura de código:
// 导入定义验证规则的模块
const joi = require('@hapi/joi')

// 定义 标题、分类Id、内容、发布状态 的验证规则
const title = joi.string().required()
const cate_id = joi.number().integer().min(1).required()
const content = joi.string().required().allow('')
const state = joi.string().valid('已发布', '草稿').required()

// 验证规则对象 - 发布文章
exports.add_article_schema = {
    
    
  body: {
    
    
    title,
    cate_id,
    content,
    state,
  },
}
  1. En /router/article.jsel módulo, importe los objetos de reglas de validación necesarios y utilícelos en el enrutamiento:
// 导入验证数据的中间件
const expressJoi = require('@escook/express-joi')
// 导入文章的验证模块
const {
    
     add_article_schema } = require('../schema/article')

// 发布新文章的路由
// 注意:在当前的路由中,先后使用了两个中间件:
//       先使用 multer 解析表单数据
//       再使用 expressJoi 对解析的表单数据进行验证
router.post('/add', upload.single('cover_img'), expressJoi(add_article_schema), article_handler.addArticle)
  1. En la función de procesamiento /router_handler/article.jsdel módulo addArticle, ifdetermine si el cliente ha enviado 封面图片:
// 发布新文章的处理函数
exports.addArticle = (req, res) => {
    
    
    // 手动判断是否上传了文章封面
  if (!req.file || req.file.fieldname !== 'cover_img') return res.cc('文章封面是必选参数!')

  // TODO:表单数据合法,继续后面的处理流程...
})

5.2.5 Implementar la función de publicar artículos.

  1. Organice los objetos de información del artículo que se insertarán en la base de datos:
// 导入处理路径的 path 核心模块
const path = require('path')

const articleInfo = {
    
    
  // 标题、内容、状态、所属的分类Id
  ...req.body,
  // 文章封面在服务器端的存放路径
  cover_img: path.join('/uploads', req.file.filename),
  // 文章发布时间
  pub_date: new Date(),
  // 文章作者的Id
  author_id: req.user.id,
}
  1. Defina la declaración SQL para publicar artículos:
const sql = `insert into ev_articles set ?`
  1. Llame db.query()para ejecutar la declaración SQL para publicar un artículo:
// 导入数据库操作模块
const db = require('../db/index')

// 执行 SQL 语句
db.query(sql, articleInfo, (err, results) => {
    
    
  // 执行 SQL 语句失败
  if (err) return res.cc(err)

  // 执行 SQL 语句成功,但是影响行数不等于 1
  if (results.affectedRows !== 1) return res.cc('发布文章失败!')

  // 发布文章成功
  res.cc('发布文章成功', 0)
})
  1. En app.js, utilice express.static()middleware para uploadsalojar las imágenes en el directorio como recursos estáticos:
// 托管静态资源文件
app.use('/uploads', express.static('./uploads'))

Por favor agregue la descripción de la imagen.
Por favor agregue la descripción de la imagen.

Supongo que te gusta

Origin blog.csdn.net/qq_66970557/article/details/128841735
Recomendado
Clasificación