Escribir a mano un árbol de decisión y una tabla de enrutamiento de contenedor http [arriba]

El padre de Linux dijo que el pseudocódigo es el mejor lenguaje porque puede expresar toda la lógica. Así que todos los ejemplos de código de este artículo son pseudocódigo.


  • Protocolo ALFP

Si tuviera que definir el protocolo http, le daría un nombre completamente diferente: ALFP (Application Layer Fetch Protocol, protocolo de solicitud de la capa de aplicación). En 2020, incluso olvidé cuál es el nombre completo de "HTTP". ¿Parece ser "Protocolo de transferencia de hipertexto"? Entonces me di cuenta de que este tipo de acrónimo antiguo que no es amigable para los recién llegados es mejor no ser leído aparte, además, la palabra "hipertexto" es poco conocida, pero al menos existe "hipertexto" en la capa de aplicación. Las cosas, junto con la palabra "buscar", pueden resumir muy vívidamente las características del protocolo http: "buscar" significa que hay una solicitud y una respuesta. Así que creo que si el protocolo HTTP se renombra al protocolo ALPF, será más amoroso. La inspiración para el cambio de nombre proviene del protocolo ALPN (negociación del protocolo de la capa de aplicación). Si el cambio de nombre es exitoso, el protocolo ALFP puede comprender rápidamente las funciones de este protocolo y reducir su aprendizaje. Costo, al mismo tiempo que satisface el trastorno obsesivo-compulsivo de la escultura de arena de nuestros viejos jugadores.

------------------------ Línea divisoria seria ---------------------- -


  • Escribir a mano un enrutador http

Se acabó el sinsentido serio, hablemos del tema. Cuando usamos Express, Koa y otros frameworks de back-end http, no podemos evitar escribir uno por nosotros mismos. Si te da pereza aprender un nuevo framework, solo para implementar una pequeña aplicación web, los frameworks de back-end escritos a mano suelen ser los mejores s Elección. Usaré nodejs para hacer el modelo de enrutamiento de back-end http más simple, para que todos entiendan que el marco web no es complicado en absoluto y todos pueden escribir a mano.

Debido a que es una versión optimizada del marco de back-end, no hay necesidad de considerar ningún equilibrio de carga y recuperación ante desastres. Solo considere el concepto central de ALFP en un servidor de máquina virtual. Las palabras clave son "capa de aplicación" y "rastreo". De esta manera, solo necesitamos considerar qué tenemos que hacer primero y luego qué hacer cuando llega una solicitud, y terminaremos una vez que se haya realizado la respuesta final. Cada paso del medio es un "middleware" independiente.

Pero para escribir un marco de back-end general, todavía necesitamos examinar qué arquitecturas tienen la mayoría de las aplicaciones web, y luego combinar estos requisitos comunes para crear nuestro propio marco web. En cuanto a los requisitos, el "diagrama de cebolla" propuesto por el framework Koa nos da algunas referencias:

No se preocupe por nada más, hay algunas funciones de back-end más importantes en el gráfico de cebolla a las que nos referimos, como enrutamiento, sesiones, almacenamiento en caché y manejo de excepciones. La arquitectura de la mayoría de las aplicaciones web son solo aquellas cosas desmontadas.

Dado que la arquitectura de front-end está básicamente unificada después de la década de 1920, no hay diferencia entre el navegador, el escritorio y los terminales móviles. Todos se denominan aplicaciones, pero las que necesitan soporte de servidor se llaman aplicaciones web, y las que no lo necesitan se llaman aplicaciones, e incluso todas La mayoría de las aplicaciones convencionales están escritas en 4 lenguajes básicos: JS, wasm, H5 y Css.

Lo anterior es la función Desde la perspectiva del rendimiento, para no bloquear el hilo principal, todo el middleware debe ejecutarse en el motor de bucle de eventos, en otras palabras, cada middleware es una promesa.


  • Árbol de decisión y tabla de enrutamiento

El middleware no solo es serial, sino que también tiene forma de árbol: el resultado del cálculo del middleware anterior puede determinar el siguiente middleware, por lo que toda la red de middleware es un árbol de decisiones y el proceso de iteración en el árbol de decisiones Se llama "enrutamiento", y la base del enrutamiento es nuestra "tabla de enrutamiento".

Hay muchas formas de tablas de enrutamiento y diferentes lógicas de negocios pueden diseñar diferentes tablas de enrutamiento. Aquí recomendamos una estrategia de uso común para construir tablas de enrutamiento basadas en los verbos Restful. Los verbos de reposo son una red de clasificación compuesta por todas las operaciones posibles sobre los datos. La conocida "adición, eliminación, modificación y búsqueda" se refiere a estos verbos. La siguiente figura muestra algunos de estos verbos:

Es una buena opción construir un árbol de decisiones basado en verbos de manipulación de datos. Los verbos se pueden escribir en el campo de encabezado del método http o en la ruta URL. En cuanto a cómo se incorpora el árbol de decisiones en el código, puede elegir un árbol if / else o una tabla hash anidada de acuerdo con el gráfico. Generalmente, la tabla hash puede hacer que cada decisión tome el mismo tiempo, lo que es más adecuado para la situación en la que el árbol de decisiones es más grande.


  • Manejo elegante de rutas de URL

Hablando de rutas, el marco de back-end generalmente almacena todas las rutas de la URL en una lista, pero debido a que las rutas de la URL están separadas por barras diagonales, para unificarlas con el separador de espacios, varias barras diagonales consecutivas se pueden considerar como una , La lista solo almacena nombres de ruta significativos, por lo que / ruta / a y / ruta // a y / ruta / a / expresan el mismo significado, y las tablas de enrutamiento correspondientes son todas ['ruta', 'a']. La expresión para generar la lista de enrutamiento es la siguiente:

// 生成路由表的伪代码
request.paths = request.urlPath.split("/").filter(p => p.trim());

request.paths es la tabla de enrutamiento, que almacena cada ruta de izquierda a derecha en la ruta de la URL. Siempre que se pasa una capa de enrutamiento, se usa paths.shift (), y luego se selecciona el siguiente middleware de acuerdo con request.paths [0].


  • Diseño de entrada (index.html)

El diseño de la entrada es muy simple, es decir, cuando la ruta URL está vacía, se debe devolver el archivo estático index.html. En este momento, request.paths es una matriz vacía.

// 网站入口的伪代码


if (request.paths.length === 0) {
  await new Promise((resolve, reject) => {
    response.setHeader("Content-Type", "text/html");


    const r = require("fs").createReadStream("path/to/index.html");
    r.on("error", err => reject(err));
    r.on("end", resolve);
    r.pipe(response);
  });
}



  • Nivel de sesión y autenticación

En muchos lugares, debemos considerar la particularidad de la entrada. Además de index.html, ¿qué es lo primero que se debe hacer después de que llega cada solicitud? Lo primero suele ser autenticar esta solicitud, ¿verdad? Ya sea autenticación por nombre de usuario y contraseña o autenticación basada en credenciales de sesión, esto es imprescindible (incluso si solicita un recurso de solo lectura).

Según las necesidades de la trama , la información de la sesión distinta de la credencial de la sesión se puede almacenar en el cliente o servidor . De todos modos, el popular formato de credenciales JWT recomienda almacenar otra información en el cliente, como la información personal de algunos usuarios. De todos modos, los datos cifrados se almacenan en el front-end sin daño, pero se puede considerar el back-end cuando el volumen de datos es grande. El siguiente es un ejemplo de almacenamiento de tokens en la interfaz:

// 会话层token认证的伪代码


module.exports = async function() {
  const req = this.request;
  const res = this.response;
  // myToken是假想的一种凭证插件,类似JWT
  const myToken = require("path/to/myToken");


  req.session = "";
  //   authorization头部用来存放加密的token
  const token = req.headers["authorization"];
  if (!token) return;


  //   secretKey是一个密钥,用于加解密token
  req.session = await myToken.verifyWithKey(token, secretKey).catch(err => {
    if (err.name === "TokenExpiredError") {
      // my-token-expire这个自定义头部提示前端应该删除这个token了
      res.setHeader("my-token-expire", 1);
    } else if (err.name === "invalidTokenError")
      throw "凭证损坏:" + err.message;
  });
};


Cuando llega la solicitud, almacenamos los datos descifrados del token que lleva en la solicitud para que los use el middleware más adelante, y también gestionamos los errores.


(Para ser continuado. . .)

Supongo que te gusta

Origin blog.csdn.net/github_38885296/article/details/104132245
Recomendado
Clasificación