nodejs+express notas de estudo

Base

revisão js

  1. Por que o javascript pode ser executado no navegador

    js a ser executado => mecanismo de análise javascript

    Diferentes navegadores têm diferentes mecanismos de análise de javascript

    1. cromo => V8 (melhor desempenho)
    2. firefox => OdinMonkey (OdinMonkey)
    3. safri => JSCore
    4. IE => Chakra (Chakra)
  2. Por que o javascript pode operar dom e bom

    1. O navegador fornece domapi, bomapi, ajaxapi
    2. Pode ser chamado pelo código js
    3. Em seguida, entregue-o ao mecanismo de análise para execução
  3. O ambiente de tempo de execução javascript do navegador

    O ambiente operacional refere-se ao ambiente necessário para o funcionamento normal do código

    Por exemplo, o ambiente operacional do navegador Chrome:

    1. motor v8

      Responsável pela análise do código javascript

    2. API integrada: dom, bom, canvas, ajax, js built-in objects, etc.

      A interface especial fornecida pelo ambiente de execução só pode ser chamada no ambiente de execução ao qual pertence

  4. O javascript pode fazer desenvolvimento de back-end

    Ele precisa estar disponível no ambiente de execução do nodejs

Conhecendo o nodejs pela primeira vez

  1. nodejs é um ambiente de tempo de execução javascript baseado no mecanismo chromeV8

  2. ambiente de tempo de execução javascript do nodejs

    1. motor v8
    2. API integrada: fs, caminho, http, objetos internos js, etc.
  3. O que os nodejs podem fazer

    Ele fornece apenas funções básicas e APIs. No entanto, com base nas funções básicas do nodejs, muitas ferramentas e estruturas poderosas surgiram, surgindo em intermináveis

    1. express: pode criar rapidamente aplicativos da web
    2. electronic: criando aplicativos de desktop multiplataforma
    3. restify: construa rapidamente projetos de interface de API
    4. Leia, escreva e manipule dados, crie ferramentas práticas de linha de comando para auxiliar no desenvolvimento de front-end
  4. caminho de aprendizagem

    1. caminho de aprendizado javascript do navegador

      1. gramática básica
      2. API integrada do navegador: bom, dom
      3. Bibliotecas de terceiros: jquery, react, vue
    2. caminho de aprendizagem nodejs

      1. gramática básica
      2. API integrada do Nodejs: fs, path, http, etc.
      3. Módulos de API de terceiros: express, mysql, etc.

API integrada

módulo do sistema de arquivos fs

  1. definição

    Um módulo fornecido oficialmente pelo nodejs para manipulação de arquivos. Ele fornece uma série de métodos e propriedades para atender às necessidades do usuário para operações de arquivo

    1. O método fs.readFile() é usado para ler o conteúdo do arquivo especificado
    2. O método fs.writeFile() é usado para gravar conteúdo no arquivo especificado
  2. usar

    const fs = require('fs');
    
  3. fs.readFile()

    fs.readFile(path[, options], callback);
    
    1. caminho: obrigatório, caminho do arquivo
    2. opções: Especifique o formato de codificação (geralmente use utf8)
    3. Callback: (err, data), geralmente use se err é nulo para julgar se a leitura foi bem-sucedida
    fs.readFile('./notes.md', 'utf-8', (err, data) => {
          
          
        if (err) {
          
          
            console.log('err :>> ', err);
            return "文件读取失败";
        }
        console.log('data :>> ', data);
        reurn "文件读取成功";
    })
    
  4. fs.writeFile()

    fs.writeFile(path, data[, options], callback);
    
    1. file: Especifica a string do caminho do arquivo (caso não exista, será criado automaticamente)
    2. dados: o conteúdo a escrever
    3. opções: formato de codificação (geralmente use utf8)
    4. retorno de chamada: (err)
    fs.writeFile("11.txt", "hello", "utf8", (err) => {
          
          
        if (err) {
          
          
            console.log('err :>> ', err);
            return "文件读取失败";
        }
        return "文件写入成功";
    });
    
  5. módulo fs - problema de emenda dinâmica de caminho

    Histórico: ao usar o módulo fs para operar arquivos, se o caminho de operação fornecido for um caminho relativo começando com ./ou ../, é fácil causar erros de emenda dinâmica de caminho

    Razão: Quando o código estiver em execução, ele será executado node命令时所处的目录e o caminho completo do arquivo operado será emendado dinamicamente

    O código é o seguinte: o caminho do código é /user/local/test.js, o arquivo a ser lido está em /user/local/notes.md, e o efeito é diferente quando está /user/localsendo executado node test.jse quando está /usersendo executadonode local/test.js

    fs.readFile('./notes.md', 'utf-8', (err, data) => {
          
          
        if (err) {
          
          
            console.log('err :>> ', err);
            return "文件读取失败";
        }
        console.log('data :>> ', data);
        return "文件读取成功";
    })
    

    solução

    1. Usar caminho absoluto: baixa portabilidade, não é propício para manutenção

    2. Use __dirnameindica o diretório absoluto onde o arquivo atual está localizado

      fs.writeFile(__dirname + "/11.txt", "hello", "utf8", (err) => {
              
              
          if (err) {
              
              
              console.log('err :>> ', err);
              return "文件读取失败";
          }
          return "文件写入成功";
      });
      

      Extensão: Se você quiser ler o arquivo da camada anterior, você precisa usá-lo path.joinpara emenda

      const path = require('path');
      const fs = require('fs');
      
      const filePath = path.join(__dirname, '../example.txt');
      fs.readFile(filePath, (err, data) => {
              
              
      if (err) throw err;
      console.log(data.toString());
      });
      

módulo caminho caminho

  1. definição

    O módulo fornecido oficialmente pelo nodejs para caminhos de processamento fornece uma série de métodos e atributos para atender às necessidades de processamento do usuário para caminhos

    1. path.join(): usado para unir os fragmentos do caminho Toohago em uma string completa
    2. path.basename(): usado para analisar o nome do arquivo da string do caminho
  2. importar

    const path = require('path');
    
  3. path.join()

    const pathStr = path.join('a', '/b', 'c', '../', 'd');
    console.log('pathStr :>> ', pathStr); // pathStr :>>  a/b/d
    
    const pathStr1 = path.join(__dirname, pathStr, "../f");
    console.log('pathStr1 :>> ', pathStr1); // /Users/xxx/Documents/code/learnningNotes/js/nodejs/testcode/a/b/f
    

    Descrição do parâmetro

    1. pode ter vários
    2. Se for ../, o último nível será removido automaticamente
    3. /aaMesmo efeito que a emenda

    Nota: Todas as operações envolvendo emenda de caminho devem ser path.join()processadas usando métodos, não use +emenda de string diretamente

  4. path.basename()

    const filePath = '/user/local/test.txt';
    let fullName = path.basename(filePath);
    console.log('fullName :>> ', fullName); // test.txt
    let nameWithoutExtension = path.basename(filePath, '.txt');
    console.log('nameWithoutExtension :>> ', nameWithoutExtension); // test
    

    Descrição do parâmetro

    1. O primeiro é o caminho do arquivo
    2. A segunda opção é a extensão removida
  5. path.extname()

    Obtenha as extensões de arquivo no caminho

    caminho.extname(caminho)

    const filePath = '/user/local/test.txt';
    let extname = path.extname(filePath);
    console.log('extname :>> ', extname); // .txt
    
  6. Caso abrangente: divida o html, o script e o estilo no index.html no diretório e coloque-os em um diretório de teste no mesmo nível

    análise passo a passo

    1. Importe os módulos necessários e crie expressões regulares

      const path = require('path');
      const fs = require('fs');
      
      const regStyle = /<style>[\s\S]*<\/style>/;
      const regScript = /<script>[\s\S]*<\/script>/;
      
    2. Use o módulo de arquivo fs para ler o arquivo html que precisa ser processado

      fs.readFile(path.join(__dirname, 'index.html'), 'utf8', (err, data) => {
              
              
          if (err) console.error('读取文件失败:', err.message);
      
          resolveCSS(data);
          resolveJS(data);
          resolveHTML(data);
      });
      
    3. Método resolveCSS personalizado

      function resolveCSS(data) {
              
              
          const r1 = regStyle.exec(data);
          const newCSS = r1[0].replace('<style>', '').replace('</style>', '');
          fs.writeFile(path.join(__dirname, 'test/index.css'), newCSS, err => {
              
              
              if (err) return console.error('写入css文件失败:', err.message);
              console.log('写入css成功');
          });
      }
      
    4. Método resolveJS personalizado

      function resolveJS(data) {
              
              
          const r1 = regScript.exec(data);
          const newJS = r1[0].replace('<script>', '').replace('</script>', '');
          fs.writeFile(path.join(__dirname, 'test/index.js'), newJS, err => {
              
              
              if (err) return console.error('写入js文件失败:', err.message);
              console.log('写入js成功');
          });
      }
      
    5. Método resolveHTML personalizado

      function resolveHTML(data) {
              
              
          const newHTML = data.replace(regStyle, '<link rel="stylesheet" href="./index.css" />')
          .replace(regScript, '<script src="./index.js"></script>');
          fs.writeFile(path.join(__dirname, 'test/index.html'), newHTML, err => {
              
              
              if (err) return console.error('写入html文件失败:', err.message);
              console.log('写入html成功');
          });
      }
      
    6. dois pontos de atenção

      1. O método path.writeFile() só pode ser usado para gravar arquivos, não para criar diretórios
      2. O método path.writeFile() é chamado repetidamente e o novo conteúdo substituirá o conteúdo antigo

módulo http

  1. O que é o módulo http

    Cliente: No nó da rede, o computador responsável por consumir os recursos.
    Servidor: Um computador responsável por fornecer recursos de rede para o mundo exterior.

    O módulo http é um módulo fornecido pelo nodejs para criar um servidor web. Através do método fornecido pelo módulo http http.createServer(), é conveniente transformar um computador comum em um servidor da Web, fornecendo assim serviços de recursos da Web para o mundo externo

  2. importar

    const http = require('http');
    
  3. Entenda a função do módulo http

    A diferença entre um servidor e um computador normal: instalado no servidor web服务器软件, como IIS, Apache, etc. Ao instalar esses softwares de servidor, um computador comum pode ser transformado em um servidor da web.

    No nodejs, não precisamos usar software de servidor da web de terceiros, como IIS e Apache, porque podemos escrever facilmente um software de servidor baseado no módulo http fornecido pelo nodejs com algumas linhas de código simples para fornecer serviços da web para o mundo lá fora.

  4. conceitos relacionados ao servidor

    1. endereço de IP

      1. É o endereço único de cada computador na Internet, portanto o endereço IP é único.
      2. Se um computador pessoal for comparado a um telefone, o endereço IP será equivalente ao número de telefone.
      3. Somente na premissa de conhecer o endereço IP da outra parte, a comunicação de dados pode ser realizada com o computador correspondente
      4. O formato do endereço IP, geralmente 点分十进制expresso na a.b.c.dforma
      5. Onde a, b, c, d são todos inteiros decimais entre 0-255, como 192.168.1.1
      6. Cada servidor web na Internet tem seu próprio endereço IP
      7. Durante o período de desenvolvimento, seu computador pode ser um servidor ou um cliente. Para facilitar o teste, você pode inserir o endereço IP 127.0.0.1 no navegador para acessar seu computador como servidor.
    2. Nomes de domínio e servidores de nomes

      1. Como o endereço IP é inconveniente de lembrar, foi inventado um esquema de endereço baseado em caracteres, que é o endereço do nome de domínio
      2. Existe uma correspondência um-para-um entre o ip e o endereço do nome de domínio, e essa correspondência é armazenada em um computador chamado servidor de nome de domínio (DNS, servidor de nome de domínio)
      3. Os usuários só precisam acessar o servidor correspondente por meio do nome de domínio fácil de lembrar, e o trabalho de conversão correspondente é realizado pelo servidor de nome de domínio
      4. Portanto, um servidor de nome de domínio é um servidor que fornece serviços de conversão entre endereços IP e nomes de domínio.
      5. Durante o período de desenvolvimento e teste, o nome de domínio correspondente a 127.0.0.1 é localhost e não há diferença no efeito de uso
    3. O número da porta

      1. O número da porta do computador é como o número da casa na vida real. Por meio do número da casa, o entregador pode entregar com precisão a entrega para você em muitos quartos em todo o prédio
      2. Em um computador, centenas de serviços da Web podem ser executados e cada serviço da Web corresponde a um número de porta exclusivo. A solicitação de rede enviada pelo cliente pode ser entregue com precisão ao serviço da Web correspondente por meio do número da porta.
      3. Cada número de porta não pode ser ocupado por vários serviços da web ao mesmo tempo
      4. Na aplicação prática, a porta 80 no URL pode ser omitida
  5. Crie o servidor web mais básico

    1. Passos básicos para criar um servidor web

      1. importar módulo http
      2. Criar uma instância do servidor web
      3. Vincule o evento de solicitação à instância do servidor e ouça a solicitação do cliente
      4. iniciar servidor
      const http = require('http');
      
      // 创建web服务器实例
      const server = http.createServer();
      
      // 为服务器实例绑定request事件,监听客户端的请求
      server.on('request', (req, res) => {
              
              
          console.log("监听到了request");
          console.log('req :>> ', req);
          console.log('res :>> ', res);
      });
      
      // 调用服务器实例的`.listen()`方法,即可启动当前的web服务器实例
      server.listen(80, () => {
              
              
          console.log('http server running at http://127.0.0.1');
      })
      
    2. objeto de solicitação req

      Enquanto o servidor receber a solicitação do cliente, ele chamará server.on()o manipulador de eventos de solicitação vinculado ao servidor

      Se você deseja acessar dados ou propriedades relacionadas ao cliente na função de processamento de eventos, pode usar o seguinte método

      server.on('request', (req, res) => {
              
              
          console.log('req.url :>> ', req.url);
          console.log('req.method :>> ', req.method);
      });
      
    3. objeto de resposta res

      Na função de processamento de eventos de solicitação do servidor, se você deseja acessar dados ou atributos relacionados ao servidor, pode usar o seguinte método

      A função do método res.end(): enviar o conteúdo especificado para o cliente e encerrar o processamento desta solicitação

      server.on('request', (req, res) => {
              
              
          res.end("Hello, world!");
      });
      
    4. Resolva o problema dos caracteres chineses distorcidos

      Ao chamar res.end()para enviar conteúdo chinês para o cliente, haverá um problema de caracteres distorcidos. Neste momento, você precisa definir manualmente o formato de codificação do conteúdo

      Ao retornar 我爱宝宝, o que recebo é鎴戠埍瀹濆疂

      Content-TypeO valor do cabeçalho de resposta precisa ser definido comotext/html;charset=utf-8

      res.setHeader('Content-Type', 'text/html;charset=utf-8');
      res.end("我爱宝宝");
      
    5. Responda a diferentes conteúdos html de acordo com diferentes urls

      server.on('request', (req, res) => {
              
              
          const url = req.url;
          let content = '<h1>404 not found</h1>';
          if (url === '/' || url === '/index.html') {
              
              
              content = '<h1>首页</h1>'
          } else if (url === '/about.html') {
              
              
              content = '<h1>关于页面</h1>';
          }
          res.setHeader('Content-Type', 'text/html; charset=utf-8');
          res.end(content);
      });
      
    6. Caso: Retorne vários arquivos da divisão index.html acima para o cliente

      const http = require('http');
      const path = require('path');
      const fs = require('fs');
      
      const server = http.createServer();
      
      // 为服务器实例绑定request事件,监听客户端的请求
      server.on('request', (req, res) => {
              
              
          console.log("进入了request");
          const url = req.url;
          console.log('url :>> ', url);
      
          let content = "";
          fs.readFile(path.join(__dirname, 'test', url), 'utf8', (err, data) => {
              
              
              console.log("进入了readFile");
              console.log('data :>> ', data);
              if (err) {
              
              
                  content = '<h1>404 not found</h1>';
              } else {
              
              
                  content = data;
              }
              // res.setHeader('Content-Type', 'text/html; charset=utf-8');
              res.end(content);
          });
      });
      
      // 启动服务器
      // 调用服务器实例的`.listen()`方法,即可启动当前的web服务器实例
      server.listen(80, () => {
              
              
          console.log('http server running at http://127.0.0.1');
      })
      

modular

conceito básico

  1. o que é modularidade

    1. Refere-se ao processo de dividir o sistema em vários módulos de cima para baixo ao resolver um problema complexo.
    2. Para todo o sistema, um módulo é uma unidade que pode ser combinada, desmontada e substituída
  2. Modularidade na programação

    Siga regras fixas e divida um arquivo grande em vários módulos pequenos independentes e interdependentes

    beneficiar

    1. Reutilização de código aprimorada
    2. Manutenibilidade de código aprimorada
    3. O carregamento sob demanda pode ser alcançado
  3. especificação modular

    São as regras que precisam ser seguidas ao dividir e combinar código

    Por exemplo

    1. Qual formato de sintaxe usar para se referir a módulos
    2. Que tipo de formato gramatical é usado no módulo para expor os membros ao mundo exterior

    beneficiar

    1. Custos de comunicação reduzidos
    2. Facilitar chamadas mútuas entre os módulos

Modularidade em nodejs

  1. Classificação

    1. Módulos integrados: fornecidos oficialmente pelo nodejs (fs, path, http)
    2. Módulos personalizados: cada arquivo js criado pelo usuário
    3. Módulos de terceiros: os módulos desenvolvidos por terceiros precisam ser baixados antes do uso
  2. módulo de carga

    Usando require()o método, você pode carregar os módulos necessários

    // 加载内置模块
    const fs = require('fs');
    // 加载自定义模块(需要指定路径)(可以省略js后缀)
    const custom = require('./custom.js');
    // 加载第三方模块
    const moment = require('moment');
    

    Nota: Ao usar o método require para carregar outros módulos, o código do módulo carregado será executado

  3. escopo do módulo

    E o escopo da função, variáveis, métodos e outros membros definidos no módulo personalizado só podem ser acessados ​​no módulo atual. Esse tipo de restrição de acesso no nível do módulo é chamado de escopo do módulo

    // customer.js
    const username = 'lan';
    function sayHello() {
          
          
        console.log("hello:", username);
    }
    
    // test.js
    const customer = require('./customer.js');
    console.log("customer", customer); // {}
    

    beneficiar

    1. Evita o problema da poluição variável global
  4. Os membros no escopo do módulo são compartilhados externamente

    1. objeto do módulo

      Existe um objeto de módulo em cada módulo personalizado, que armazena informações relacionadas ao módulo atual

      Module {
              
              
          id: '.',
          path: '/Users/feng.lan/Documents/code/learnningNotes/js/nodejs/testcode',
          exports: {
              
              },
          filename: '/Users/feng.lan/Documents/code/learnningNotes/js/nodejs/testcode/module.js',
          loaded: false,
          children: [
              Module {
              
              
                  id: '/Users/feng.lan/Documents/code/learnningNotes/js/nodejs/testcode/customer.js',
                  path: '/Users/feng.lan/Documents/code/learnningNotes/js/nodejs/testcode',
                  exports: {
              
              },
                  filename: '/Users/feng.lan/Documents/code/learnningNotes/js/nodejs/testcode/customer.js',
                  loaded: true,
                  children: [],
                  paths: [Array]
              }
          ],
          paths: [
              '/Users/feng.lan/Documents/code/learnningNotes/js/nodejs/testcode/node_modules',
              '/Users/feng.lan/Documents/code/learnningNotes/js/nodejs/node_modules',
              '/Users/feng.lan/Documents/code/learnningNotes/js/node_modules',
              '/Users/feng.lan/Documents/code/learnningNotes/node_modules',
              '/Users/feng.lan/Documents/code/node_modules',
              '/Users/feng.lan/Documents/node_modules',
              '/Users/feng.lan/node_modules',
              '/Users/node_modules',
              '/node_modules'
          ]
      }
      
    2. objeto module.exports

      Em um módulo personalizado, module.exportsos objetos podem ser usados ​​para compartilhar os membros do módulo para uso externo

      Quando o mundo exterior usa require()módulos personalizados importados, o que ele obtém é module.exportso objeto ao qual ele se refere

      Nota: require()Ao usar o módulo de importação, o resultado da importação sempre estará module.exportssujeito ao objeto apontado

      const username = "lan";
      function sayHello() {
              
              
          console.log("hello:", username);
      }
      
      module.exports.nickname = 'feng';
      module.exports.printName = function() {
              
              
          console.log("printName");
      }
      
      module.exports = {
              
              
          username,
          sayHello
      }
      
    3. exporta objeto

      Como a palavra module.exports é mais complicada de escrever, para simplificar o código para compartilhar membros, o nodejs fornece um objeto exports. Por padrão, exports e module.exports apontam para o mesmo objeto

      O resultado final compartilhado ainda está sujeito ao objeto apontado por module.exports

    4. Mal-entendidos no uso de exports e module.exports

      console.log(module.exports === exports); // true
      

      Ponto-chave: Quando o objeto de referência não for alterado novamente, os dois são iguais, mas uma vez que um deles altere o objeto de referência, ele module.exportsprevalecerá

      Tenha sempre em mente que quando você requer() um módulo, você sempre obterá o objeto apontado por module.exports

      module.exports.username = 'lan';
      exports.age = 12;
      
      // 这种情况下获取到的是 {username: 'lan', age: 12}
      
      module.exports.username = 'lan';
      
      exports = {
              
              
          gender: '男',
          age: 12
      }
      
      // 这种情况下获取到的是 {name: 'lan'}
      
      exports.usename = 'lan';
      
      module.exports = {
              
              
          gender: 'man',
          age: 12
      }
      
      // 这种情况得到的是 {gender: 'man', age: 12}
      
  5. Especificação modular em nodejs

    Siga a especificação modular do commonjs, que estipula as características dos módulos e como cada módulo depende do outro

    1. Dentro de cada módulo, a variável do módulo representa o módulo atual
    2. A variável do módulo é um objeto e sua propriedade exports (ou seja, module.exports) é uma interface externa
    3. Carregar um módulo é, na verdade, carregar o atributo module.exports do módulo, e o método require() é usado para carregar o módulo

Bolsa

  1. o que é um pacote

    Módulos de terceiros em nodejs são chamados de pacotes

  2. fonte do pacote

    Desenvolvido por indivíduos ou equipes de terceiros, gratuito para todos usarem

    Nota: Os pacotes no nodejs são todos gratuitos e de código aberto, e você pode baixá-los e usá-los gratuitamente sem pagar

  3. por que você precisa de um pacote

    1. Como os módulos integrados do nodejs fornecem apenas algumas APIs de baixo nível, a eficiência do desenvolvimento de projetos com base em módulos integrados é muito baixa
    2. Os pacotes são encapsulados com base em módulos integrados, fornecendo APIs mais avançadas e convenientes, o que melhora muito a eficiência do desenvolvimento
    3. A relação entre pacotes e módulos integrados é semelhante à relação entre jQuery e APIs integradas do navegador
  4. onde baixar o pacote

    Pesquisar: site https://www.npmjs.com/, ele é a maior plataforma de compartilhamento de pacotes do mundo, você pode pesquisar qualquer pacote que precise neste site

    Download: através https://registry.npmjs.org/do servidor para compartilhar todos os pacotes, podemos baixar os pacotes que precisamos deste servidor

  5. Como baixar o pacote

    Ferramenta de gerenciamento de pacotes: ferramenta de gerenciamento de pacotes npm (Node Package Manager), esta ferramenta é instalada no computador do usuário junto com o pacote de instalação nodejs

  6. Quais arquivos são adicionados após a primeira instalação do pacote

    1. node_modules: armazena todos os pacotes instalados no projeto
    2. package-lock.json: Registre as informações de download (nome, número da versão, endereço de download) de cada pacote no diretório node_modules
  7. Instale a versão especificada

    Por padrão, a versão mais recente é instalada, se você precisar especificar a versão, use@

    npm i moment@2.22.2
    
  8. Especificação de versão semântica do pacote

    点分十进制Definido na forma de , há um total de 3 dígitos, como2.22.2

    1. Primeiro dígito: versão grande
    2. Segundo dígito: versão do recurso
    3. Terceiro dígito: versão de correção de bug

    Regra de promoção do número da versão: enquanto o número da versão anterior aumentar, o número da versão subsequente será redefinido para zero

  9. Arquivo de configuração de gerenciamento de pacotes

    O Npm estipula que no diretório raiz do projeto package.jsondeve ser fornecido um arquivo de configuração de gerenciamento de pacotes chamado "arquivo de configuração de gerenciamento de pacotes" para registrar algumas informações de configuração relacionadas ao projeto, como

    1. Nome do projeto, número da versão, descrição, etc.
    2. Quais outros pacotes são usados ​​no projeto
    3. Quais pacotes são usados ​​apenas durante o desenvolvimento
    4. Quais pacotes são usados ​​durante o desenvolvimento e implantação

    Crie rapidamentepackage.json

    npm init -y

    Obs: Os comandos acima só podem 英文ser executados no diretório, então o nome da pasta do projeto deve ser nomeado em inglês, não use chinês, e não apareçam espaços

    dependencies: Usado para registrar quais pacotes foram instalados

    devDependencies: usado apenas durante a fase de desenvolvimento do projeto, não após o projeto ficar online

     ```js
     npm i webpack -D
    
     npm install webpack --save--dev
     ```
    
  10. a velocidade de download do npm é lenta

    1. Razão: O padrão é baixar de um https://registry.npmjs.orgservidor externo. Neste momento, a transmissão de dados da rede precisa passar por um longo cabo óptico submarino

    2. Solução: servidor espelho Taobao npm

      Taobao configurou um servidor na China para sincronizar os pacotes em servidores oficiais estrangeiros para servidores domésticos e, em seguida, fornecer o serviço de download de pacotes na China, o que melhora muito a velocidade de download de pacotes

      Mude a fonte espelho de download do npm

       ```shell
       # 查看当前下包镜像源
       npm config get registry
      
       # 将下包的镜像源切换为淘宝镜像源
       npm config get registry=https://registry.npm.taobao.org/
       ```
      
    3. nrm

      Para alternar convenientemente a fonte da imagem do pacote, podemos instalar a pequena ferramenta nrm e usar o comando de terminal fornecido pelo nrm para visualizar e alternar rapidamente a fonte da imagem do pacote

      npm i nrm -g
      nrm ls
      nrm use taobao
      

      possíveis erros

      /opt/homebrew/Cellar/nvm/0.39.1_1/versions/node/v16.18.0/lib/node_modules/nrm/cli.js:9
      const open = require('open');
                  ^
      
      Error [ERR_REQUIRE_ESM]: require() of ES Module /opt/homebrew/Cellar/nvm/0.39.1_1/versions/node/v16.18.0/lib/node_modules/nrm/node_modules/open/index.js from /opt/homebrew/Cellar/nvm/0.39.1_1/versions/node/v16.18.0/lib/node_modules/nrm/cli.js not supported.
      Instead change the require of index.js in /opt/homebrew/Cellar/nvm/0.39.1_1/versions/node/v16.18.0/lib/node_modules/nrm/cli.js to a dynamic import() which is available in all CommonJS modules.
          at Object.<anonymous> (/opt/homebrew/Cellar/nvm/0.39.1_1/versions/node/v16.18.0/lib/node_modules/nrm/cli.js:9:14) {
              
              
      code: 'ERR_REQUIRE_ESM'
      }
      

      A razão é que o openpacote correspondente está faltando

      // 这里好像要这个版本才行,我安装最新的版本也没有解决
      npm install -g nrm open@8.4.2 --save
      
  11. Estrutura do pacote canônico

    1. Os pacotes devem existir como diretórios separados
    2. package.jsonO arquivo de configuração de gerenciamento de pacotes deve ser incluído no diretório de nível superior do pacote
    3. package.jsondeve conter name, version, mainesses 3 atributos, representando o nome, número da versão, entrada
  12. Desenvolva seu próprio pacote

    1. Inicializar package.json

      {
              
              
      "name": "lan-tools",
      "version": "1.0.0",
      "description": "feng.lan测试包",
      "main": "index.js",
      "scripts": {
              
              
          "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": ["feng", "lan"],
      "author": "feng.lan",
      "license": "ISC"
      }
      
    2. Inicialize seu próprio código em index.js e exponha os membros correspondentes

      function printInfo() {
              
              
          console.log("这里是feng.lan的测试函数");
      }
      
      function sayHello(name) {
              
              
          console.log("hello " + name);
      }
      
      module.exports = {
              
              
          printInfo,
          sayHello,
      }
      
    3. Documentação para escrever pacotes

      README.mdarquivos no diretório raiz do pacote

      ### 安装
      
      > npm install lan-tools
      
      ### 导入
      
      > const lanTools = require('lan-tools');
      
      ### 输出信息
      
      > lanTools.printInfo();
      
      ### sayHello
      
      > lanTools.sayHello("feng.lan");
      
    4. pacote de lançamento

      1. Registrar conta npm

      2. Use npm logino comando no terminal para inserir o nome de usuário, senha, endereço de e-mail e código de verificação de e-mail em sequência para efetuar login com sucesso.

        Problema existente: Ao fazer login, você precisa definir o package warehouse como a fonte oficial do npm, porque o login é baseado na sua configuração, caso contrário, por exemplo, se você for uma fonte Taobao, ele solicitará que você faça login no Taobao fonte, então sua conta npm registrada não pode fazer login

         ```shell
         npm WARN adduser `adduser` will be split into `login` and `register` in a future version. `adduser` will become an alias of `register`. `login` (currently an alias) will become its own command.
         npm notice Log in on https://registry.npm.taobao.org/
         ```
        
      3. Depois de mudar o terminal para o diretório raiz do pacote, executenpm publish

    5. remover pacotes publicados

      npm unpublish 包名 --force
      

      Perceber

      1. Somente pacotes publicados em 72 horas podem ser excluídos
      2. Nenhuma repostagem permitida dentro de 24 horas

Mecanismo de Carregamento do Módulo

  1. Priorizar o carregamento do cache

    Os módulos são armazenados em cache após o primeiro carregamento, o que também significa que várias chamadas require()não farão com que o código do módulo seja executado várias vezes

    Seja um módulo integrado, um módulo definido pelo usuário ou um módulo de terceiros, eles serão carregados do cache primeiro, melhorando assim a eficiência de carregamento do módulo

  2. Mecanismo de carregamento para módulos integrados

    Os módulos integrados têm a maior prioridade de carregamento

    Mesmo que o módulo personalizado tenha fsum módulo com o mesmo nome, o fsmódulo nodejs oficial é carregado

  3. Mecanismo de carregamento para módulos personalizados

    O identificador de caminho deve começar com ./ou ../, se não houver ./ou ../, o nó irá carregá-lo como um módulo interno ou um módulo de terceiros

    Se a extensão do arquivo for omitida, o nodejs tentará carregar os seguintes arquivos em ordem

    1. 确切的文件名carregar de acordo com
    2. Extensão completa .jspara carregar
    3. .jsonConclusão de extensões para carregamento
    4. .nodeConclusão de extensões para carregamento
    5. Falha ao carregar, o terminal relatou um erro
  4. Mecanismo de carregamento para módulos de terceiros

    nodejs iniciará a partir do diretório pai do módulo atual e tentará /node_modulescarregar módulos de terceiros a partir do diretório

    Se o módulo de terceiros correspondente não for encontrado, vá para o próximo diretório pai e carregue-o até o diretório raiz do sistema de arquivos

    Por exemplo, se /user/local/project/foo.jsfor chamado em require('tools'), o nodejs pesquisará na seguinte ordem

    1. /user/local/project/node_modules/tools
    2. /user/local/node_modules/tools
    3. /user/node_modules/tools
    4. /node_modules/ferramentas
  5. diretório como módulo

    Quando o diretório é passado como identificador do módulo a require()ser carregado, existem 3 métodos de carregamento

    1. Pesquise no diretório carregado package.jsone procure mainatributos como require()a entrada
    2. index.jsSe não estiver na etapa anterior, procure os arquivos no diretório
    3. Se as duas etapas acima falharem, um erro será relatado no terminalError: Cannot find module 'xxx'

expressar

expresso inicial

  1. definição

    1. Oficial: Baseado na plataforma nodejs, um framework de desenvolvimento web rápido, aberto e minimalista
    2. Vernacular: Semelhante ao módulo http embutido, é usado especialmente para criar servidores web
    3. Essência: É um pacote de terceiros no npm, que fornece uma maneira conveniente de criar rapidamente um servidor web

    Site oficial: https://www.expressjs.com.cn/

    1. mais compreensão

      O módulo embutido http embutido é muito complicado de usar e a eficiência do desenvolvimento é baixa

      O Express é ainda mais encapsulado com base no módulo http integrado, o que pode melhorar muito a eficiência do desenvolvimento

    2. o que os especialistas podem fazer

      1. Servidor de site da Web: um servidor dedicado a fornecer recursos de página da Web para o mundo externo
      2. servidor de interface api: um servidor dedicado a fornecer interface api para o mundo exterior
  2. Instalar

    npm eu expresso`

  3. uso 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 and listening on 80')
    })
    
  4. Ouça para receber e postar solicitações e retornar o conteúdo da resposta

    const express = require('express');
    
    const app = express();
    
    app.listen(80, () => {
          
          
        console.log('express server running at http://127.0.0.1 and listening on 80')
    })
    
    app.get('/getMethods', (req, res) => {
          
          
        console.log('getMethods');
        res.send({
          
          
            type: 'get',
            name: 'lan',
            age: 12
        })
    })
    
    app.post('/postMethods', (req, res) => {
          
          
        console.log('postMethods');
        res.send({
          
          
            type: 'post',
            name: 'lan',
            age: 12
        })
    })
    
  5. Obtenha os parâmetros de consulta do URL

    app.get('/getMethods', (req, res) => {
          
          
        const params = req.query;
        res.send(params)
    })
    
  6. Obter parâmetros dinâmicos no URL

    Ao :combinar parâmetros dinâmicos

    Por exemplo, a interface /user/:idé usada para consultar uma determinada informação do usuário

    app.get('/user/:id', (req, res) => {
          
          
        const params = req.params;
        res.send(params);
    })
    
    // 可以多个动态参数拼接
    app.get('/user/:id/:username', (req, res) => {
          
          
        const params = req.params;
        res.send(params);
    })
    

Hospedando recursos estáticos

  1. express.static()

    O Express fornece uma função muito útil chamada, express.statis()por meio dela, podemos criar um servidor de recursos estáticos de maneira muito conveniente, por exemplo, por meio do código a seguir, as pulbicimagens, arquivos css e arquivos js no diretório podem ser abertos para o mundo externo

     ```js
     // 目录位置相对于根目录
     app.use(express.static('public'));
    
     // url访问方式 public/demo.js
     // http://127.0.0.1/demo.js
     ```
    
  2. Hospede vários diretórios de recursos estáticos, chame-o várias vezes

    app.use(express.static('public'));
    app.use(express.static('static'));
    
  3. prefixo do caminho de montagem

    Se você deseja acessar recursos estáticos, adicione o prefixo do caminho

     ```js
     app.use('/public', express.static('public'));
     ```
    

    Nota: /publico /essencial

nodemon

  1. efeito

    Ao escrever e depurar um projeto nodejs, se você modificar o código do projeto, precisará fechá-lo manualmente com frequência e reiniciá-lo, o que é muito complicado

    o nodemon pode monitorar as alterações dos arquivos do projeto e reiniciará automaticamente o projeto após ser modificado

  2. Instalar

    npm install -g nodemon
    
  3. usar

    node index.jsO comando de partida mudou denodemon index.js

roteamento

  1. conceito

    refere-se a 客户端的请求entre服务器处理函数映射关系

    Consiste em 3 partes, o tipo de solicitação, o endereço URL da solicitação e a função de processamento

    app.METHOD(PATH, HANDLER);
    
    app.get('/', () => console.log('get请求'));
    app.post('/', () => console.log('post请求'));
    
  2. processo de correspondência de rota

    Sempre que uma solicitação chega ao servidor, ela precisa primeiro passar pela correspondência de rota e, somente depois que a correspondência for bem-sucedida, a função de processamento correspondente será chamada

    1. 先后顺序corresponder conforme definido
    2. 请求类型E 请求的urlprecisa ser 同时匹配bem-sucedido, chamará a função de processamento correspondente
  3. a rota mais fácil

    montar diretamente appem

    app.get('/', () => console.log('get请求'));
    app.post('/', () => console.log('post请求'));
    
  4. Modularidade de Roteamento

    Para facilitar a gestão modular das rotas, 不建议直接将路由挂载到app上em vez推荐将路由抽离为单独的模块

    1. ./jsCrie o arquivo correspondente ao módulo de roteamento
    2. Função de chamada express.Router()para criar objeto de rota
    3. Monte uma rota específica para o objeto de rota
    4. Usar module.exports()objetos de roteamento compartilhados de saída
    5. app.use()Registre um módulo de roteamento com uma função
    // router.js
    const express = require('express');
    // 创建路由对象
    const router = express.Router();
    
    // 挂载路由
    router.get('/user/list', (req, res) => {
          
          
        res.send('get user list');
    })
    router.post('/user/add', (req, res) => {
          
          
        res.send('add new user');
    })
    
    // 向外导出路由对象
    module.exports = router;
    
    const express = require('express');
    const router = require('./router.js');
    
    const app = express();
    
    // 注册路由模块,全剧中间件
    app.use(router);
    
    app.listen(80, () => {
          
          
        console.log('express server running at http://127.0.0.1 and listening on 80')
    })
    
  5. Adicionar um prefixo à rota

    app.use('/api', router);
    

middleware

  1. definição

    Quando uma solicitação chega ao servidor expresso, vários middlewares podem ser chamados continuamente, para que a solicitação possa ser processada预处理

    Essencialmente um 处理函数, o middleware é 格式o seguinte

     ```js
     app.get('/', (req, res, next) => {
         /* some code */
         next();
     })
     ```
    

    Observação: a lista de parâmetros formais da função de middleware deve conter next参数, enquanto os parâmetros de processamento de roteamento contêm apenas req e res

  2. O papel da próxima função

    É a chave para a realização 多个中间件连续调用, significa dar a relação de fluxo 转交para o próximo middleware ou rota

  3. Definir funções de middleware

    const express = require('express');
    const router = require('./router.js');
    
    const app = express();
    
    const mw = (req, res, next) => {
          
          
        console.log('最简单的中间件');
        next();
    }
    
    // 全局生效的中间件
    app.use(mw);
    
    app.use('/api', router);
    
    app.listen(80, () => {
          
          
        console.log('express server running at http://127.0.0.1 and listening on 80')
    })
    
  4. Middleware global

    Middleware iniciado pelo cliente 任何请求e chegando ao servidor都会触发

    Ao passar app.use(wm), você pode definir um middleware eficaz globalmente

     ```js
     app.use(mw);
     ```
    

    Definir middleware global múltiplo Após a solicitação do cliente chegar ao servidor, ele será chamado em sequência de acordo com a ordem em que o middleware for definido.

     ```js
     app.use((req, res, next) => {
         console.log('调用了第一个中间件');
         next();
     })
    
     app.use((req, res, next) => {
         console.log('调用了第二个中间件');
         next();
     })
     ```
    

    efeito

    1. Vários middlewares compartilham o mesmo res e req
    2. Com base nesse recurso, podemos adicionar propriedades ou métodos personalizados uniformemente aos objetos req e res no middleware upstream para uso pelo middleware downstream ou roteamento
  5. middleware válido localmente

    nenhum app.use()middleware definido

     ```js
     const mw = (req, res, next) => {
         console.log('局部生效的中间件');
         next();
     }
    
     // 挂载路由
     router.get('/user/list', mw, (req, res) => {
         console.log('startTime', req.startTime)
         res.send({
             txt: 'get user list',
             date: req.startTime
         });
     })
     ```
    

    Definir middleware parcial múltiplo

     ```js
    
     // 方式一:使用数组
     router.get('/user/list', [mw1, mw2, mw3], (req, res) => {})
     // 方式二:多个参数
     router.get('/user/list', mw1, mw2, mw3, (req, res) => {})
     ```
    
  6. Algumas notas

    1. Certifique-se de registrar o middleware antes do roteamento (o middleware de nível de erro deve estar após todas as rotas)
    2. A solicitação enviada pelo cliente pode chamar vários middlewares continuamente para processamento
    3. deve ser chamado na função do manipuladornext()
    4. Para evitar confusão lógica de código, next()não escreva código adicional após chamar a função
    5. Quando vários middlewares são chamados continuamente, os objetos req e res são compartilhados entre vários middlewares
  7. Classificação de middleware

    1. Middleware de nível de aplicativo

      Por meio de app.use(), app.get()ou app.post(), middleware vinculado à instância do aplicativo

    2. Middleware de nível de rota

      Middleware vinculado à express.Router()instância

      Não há diferença entre middleware de nível de aplicativo e uso, exceto que 应用级别是绑定到app实例上,路由级别是绑定到router实例上

    3. middleware de nível de erro

      É especialmente usado para detectar erros anormais que ocorrem no projeto, de modo a evitar o problema de falha anormal do projeto

      Formato: deve ter 4 parâmetros formais (err, req, res, next)

       ```js
       const express = require('express');
       const app = express();
      
       const mw = (err, req, res, next) => {
           console.log('发生了错误', err.message);
           res.send({
               code: 500,
               msg: err.message
           })
       }
      
       app.use('/user/list', (req, res) => {
           throw new Error('服务器错误了');
           res.send('data');
       });
      
       app.use(mw);
      
       app.listen(80, () => {
           console.log('express server running at http://127.0.0.1 and listening on 80')
       })
       ```
      

      必须要在所有路由之后

    4. middleware integrado expresso

      3个Desde a versão express4.16.0, middleware comum integrado

      1. express.static Middleware integrado para hospedagem rápida de recursos estáticos, como arquivos html, imagens, etc. ( 完全兼容)

      2. express.json analisa os dados da solicitação no formato json ( 4.16.0+)

      3. express.urlencoded analisa dados de solicitação codificados por URL ( 4.16.0+)

        Por padrão, se nenhum middleware para análise de dados do formulário for configurado, ele será req.bodyigual a indefinido por padrão

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

      Não é um nodejs integrado oficial, mas um middleware desenvolvido por terceiros

      Por exemplo, body-parsereste middleware

      1. npm install body-parser
      2. requireimportar
      3. app.use()Registre-se e use

      Analisar o middleware de dados em dados de formulário

      const multipart = require('connect-multiparty');
      const multipartMiddleware = multipart();
      app.use(multipartMiddleware);
      
      app.post('/api/login', (req, res) => {
              
              
          const data = req.body;
          res.send(data);
      })
      
  8. Implementação de middleware personalizado

    Descrição: simule manualmente um express.urlencoded semelhante para analisar os dados do formulário enviados pela postagem ao servidor

    Etapas de implementação

    1. Definir middleware

    2. Ouça o evento de dados de req

      Se a quantidade de dados for muito grande para ser enviada de uma só vez, o cliente cortará os dados e os enviará ao servidor em lotes, de modo que o evento de dados possa ser acionado várias vezes. Cada vez que um evento de dados é acionado, é apenas uma parte dos dados completos. Juntando manualmente os dados recebidos

    3. Ouça o evento final de req

      Quando os dados do corpo da solicitação são recebidos, o evento final de req será acionado automaticamente

    4. Use o módulo querystring para analisar os dados do corpo da solicitação

      O Nodejs possui um módulo embutido querystring, que é usado especialmente para a função 处理查询字符串deste módulo parse(), que pode facilmente analisar a string de consulta no formato do objeto

    5. Monte o objeto de dados analisados ​​como req.body

    6. Empacotar middleware customizado como um módulo

      app.use((req, res, next) => {
              
              
          console.log('进入了自定义中间件')
          let str = "";
          req.on('data', (chunk) => {
              
              
              console.log('chunk :>> ', chunk);
              str += chunk;
          })
          req.on('end', () => {
              
              
              console.log('完整数据', str);
              const data = qs.parse(str);
              console.log('data :>> ', data);
              req.body = data;
              next();
          })
      })
      
  9. Use express para escrever a interface

    1. obter interface

      router.get('/user/list', (req, res) => {
              
              
          res.send({
              
              
              status: 200,
              data: req.query,
              msg: 'GET 请求成功',
          });
      })
      
    2. pós-interface

      router.post('/user/add', (req, res) => {
              
              
          res.send({
              
              
              status: 200,
              data: req.body,
              msg: 'POST 请求成功',
          });
      })
      

compartilhamento de recursos entre domínios cors

  1. Background
    As interfaces get e post acima,不支持跨于请求

    Existem basicamente duas soluções

    1. cors (solução convencional, recomendada)
    2. jsonp (somente suporta get)

    Usar middleware cors

     ```js
     const cors = require('cors');
     app.use(cors());
     ```
    
  2. limite

    1. Configurado no lado do servidor, o navegador do cliente pode solicitar uma interface com cors habilitada sem qualquer configuração adicional

    2. Há compatibilidade em navegadores, apenas XMLHttpRequest Level2navegadores suportados podem usar cors (IE10+, Chrome4+, FireFox3.5+)

    3. Acesso-Controle-Permitir-Origem

      // 请求头
      Access-Control-Allow-Origin: <origin> | *
      
      // 实际设置
      res.setHeader('Access-Control-Allow-Origin', '*');
      
    4. Acesso-Controle-Permitir-Cabeçalhos

      Por padrão, o cors suporta apenas o cliente enviando os 9 cabeçalhos de solicitação a seguir para o servidor

      1. Aceitar
      2. Aceitar-Idioma
      3. Idioma do conteúdo
      4. DPR
      5. Downlink
      6. Guardar dados
      7. Largura da Janela de Visualização
      8. Largura
      9. Content-Type (o valor é limitado a um de text/plain, multipart/form-data, application/x-www-form-urlencoded)

      Se o cliente enviar informações de cabeçalho de solicitação adicionais para o servidor, elas precisam ser Access-Control-Headersverificadas no lado do servidor por meio do cabeçalho de solicitação adicional 声明, caso contrário, a solicitação falhará desta vez

       ```js
       // 多个请求头之间使用英文的逗号进行分割
       res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Custom-Header');
       ```
      
    5. Acesso-Controle-Permitir-Métodos

      Por padrão, o cors suporta apenas clientes para iniciar solicitações get, post, head

      Se o cliente deseja solicitar recursos do servidor por meio de put, delete, etc., ele precisa Access-Control-Allow-Methodsindicar o método http permitido pela solicitação real no lado do servidor por

       ```js
       res.setHeader('Access-Control-Allow-Methods', 'GET POST DELETE HEAD');
       res.setHeader('Access-Control-Allow-Headers', '*');
       ```
      
  3. pedido simples

    Uma solicitação que satisfaça as duas condições a seguir ao mesmo tempo é uma solicitação simples

    1. Método de solicitação: um de GET, POST, HEAD
    2. As informações do cabeçalho http u excedem os seguintes campos ( 无自定义头部字段)
      1. Aceitar
      2. Aceitar-Idioma
      3. Idioma do conteúdo
      4. DPR
      5. Downlink
      6. Guardar dados
      7. Largura da Janela de Visualização
      8. Largura
      9. Content-Type (o valor é limitado a um de text/plain, multipart/form-data, application/x-www-form-urlencoded)
  4. solicitação de simulação

    Desde que a solicitação atenda a qualquer uma das condições a seguir, uma solicitação de comprovação é necessária

    1. 之外O método de solicitação é GET, POST, HEAD
    2. O cabeçalho da solicitação contém 自定义头部campos
    3. Enviou application/jsonos dados formatados para o servidor

    Antes da comunicação formal entre o navegador e o servidor, o navegador primeiro enviará OPTIONuma solicitação de pré-verificação para obter se o servidor permite a solicitação real, portanto, desta vez, OPTIONa solicitação é chamada de solicitação de pré-verificação 服务器成功响应预检请求之后e só então o solicitação real seja enviada e carregue os dados reais

  5. jsonp

    Conceito: O navegador solicita dados no servidor através dos atributos <script>do rótulo e, ao mesmo tempo, o servidor retorna uma chamada de função. Esse método de solicitação de dados é chamado de jsonpsrc

    Características:

    1. jsonp não é uma requisição ajax real, pois ele não usa o objeto XMLHttpRequest
    2. jsonp suporta apenas solicitações GET, não POST, PUT, DELETE e outras solicitações
    // 必须要cors中间件之前,配置jsonp接口
    app.get('/api/jsonp', (req, res) => {
          
          
        // 1. 获取客户端发送过来的回调函数的ing子
        const callback = req.query.callback;
        // 2. 得到要通过jsonp形式发送给客户端的数据
        const data = {
          
          
            name: 'lan',
            age: 12
        }
        // 3. 根据前两步得到的数据,拼接出一个函数调用的字符串
        const str = `${
            
            callback}(${
            
            JSON.stringify(data)})`
        // 4. 把上一步拼接得到的字符串,响应给客户端的script标签进行解析
        res.send(str);
    })
    
    function jsonpHandle() {
          
          
        $.ajax({
          
          
            url: 'http://127.0.0.1/api/jsonp',
            dataType: 'jsonp',
            jsonpCallback: 'myCallback',
            success: function(data) {
          
          
                console.log(data);
            },
            error: function(jqXHR, textStatus, errorThrown) {
          
          
                console.error(errorThrown);
            }
        });
    }
    function myCallback(data) {
          
          
        console.log('执行了myCallback', data);
    }
    

Banco de dados e autenticação

Conceitos básicos de banco de dados

  1. definição

    Um warehouse para organizar, armazenar e gerenciar dados

    Pode adicionar, excluir, modificar e consultar os dados no banco de dados

  2. Bancos de dados e classificações comuns

    1. MySql: O mais amplamente aplicável e mais popular (versão gratuita + versão paga)
    2. Oráculo: Taxas
    3. SQL Server: cobrado
    4. Mongodb: versão gratuita + versão paga

    Banco de dados relacional: MySql, Oracle, SQL Server

    Banco de dados não relacional: Mongodb

  3. Estrutura de organização de dados do banco de dados tradicional

    1. base de dados
    2. Ficha de dados
    3. linha de dados
    4. campo

    relação

    1. No desenvolvimento real do projeto, em circunstâncias normais, cada projeto corresponde a um banco de dados independente
    2. Dados diferentes devem ser armazenados em tabelas diferentes
    3. Quais informações são armazenadas em cada tabela são determinadas pelo campo
    4. As linhas na tabela representam cada parte específica dos dados

Instalar e configurar MySql

  1. software necessário

    1. MySql Server: software dedicado a fornecer armazenamento de dados e serviços
    2. Navicat: ferramenta de gerenciamento Visual MySql
  2. Instalar mysql e navicat

    mysql: https://blog.csdn.net/weixin_44427181/article/details/127552892

    mysql -uroot -p

    navegação:

    1. Baixar: https://www.jb51.net/softs/805270.html#downintro2
    2. Tutorial: https://www.cnblogs.com/fdw630/p/16956894.html

    Usando navicat para conectar ao banco de dados encontrou um erro

    1. 1045 - Acesso negado para usuário 'root'@'localhost' (usando senha: SIM)

      Referência: https://zhuanlan.zhihu.com/p/158806221

    2. mac 2002 - Não é possível conectar ao servidor em '127.0.0.1' (36)

      Reiniciei o computador e estava tudo bem. . .

  3. Os comandos de banco de dados mais básicos

    // 登陆数据库
    mysql -u root -p
    // 显示数据库
    show databases;
    // 创建数据库
    create database MyDB_one;
    // 设置编码
    create database MyDB_three charset utf8;
    // 查看数据库信息
    show create database MyDB_one;
    // 进入或者切换数据库
    use MyDB_one
    // 显示表
    show tables;
    // 创建表
    create table Phone_table(pid INT, name CHAR(20), price INT);
    // 增加字段
    alter table Phone_table add color CHAR(20);
    
  4. Instalação e configuração do módulo MySQL no express

    npm install mysql
    
    // 1. 导入mysql模块
    const mysql = require('mysql');
    // 2. 建立与mysql数据库的连接
    const db = mysql.createPool({
          
          
        host: '127.0.0.1',
        user: 'root',
        port: 3306,
        password: 'feng.lan',
        database: 'user',
    })
    
    db.query('select * from user', (err, res) => {
          
          
        if (err) return console.error('err----', err);
        console.log('res-----', res);
    })
    

operações comuns do mysql

```js
// 查询
db.query('select * from user', (err, res) => {
    if (err) return console.error('err----', err.message);
    console.log('res-----', res);
})

const user = {
    name: '王五',
    age: 15
}
// 插入(按字段插入)
const sqlStr = 'INSERT INTO user (name, age) VALUES (?, ?)';
db.query(sqlStr, [user.name, user.age], (err, res) => {
    if (err) return console.error('err----', err.message);
    if (res.affectedRows === 1) {
        console.log('插入数据成功', res);
    }
})
// 插入(按行插入)需要对象的每个属性和字段一一对应
const sqlStr1 = 'INSERT INTO user SET ?';
db.query(sqlStr1, user, (err, res) => {
    if (err) return console.error('err----', err.message);
    if (res.affectedRows === 1) {
        console.log('插入数据成功', res);
    }
})

// 更新
const user = {
    id: 1,
    name: '张三一',
    age: 1
}
const sqlStr = 'UPDATE user SET name = ?, age = ? WHERE id = ?';
db.query(sqlStr, [user.name, user.age, user.id], (err, res) => {
    if (err) return console.error('err----', err.message);
    if (res.affectedRows === 1) {
        console.log('更新数据成功', res);
    }
})
// 快捷更新
const sqlStr1 = 'UPDATE user SET ? WHERE id = ?';
db.query(sqlStr1, [user, user.id], (err, res) => {
    if (err) return console.error('err----', err.message);
    if (res.affectedRows === 1) {
        console.log('更新数据成功', res);
    }
})

// 删除
const sqlStr = 'DELETE FROM user WHERE id = ?';
db.query(sqlStr, 1, (err, res) => {
    if (err) return console.error('err----', err.message);
    if (res.affectedRows === 1) {
        console.log('删除数据成功', res);
    }
})
```

Autenticação front-end e back-end

  1. modelo de desenvolvimento web

    1. renderização do lado do servidor

      A página html enviada pelo servidor para o cliente é gerada dinamicamente pelo servidor por meio de emenda de string

      Portanto, o cliente não precisa de tecnologias como ajax para solicitar dados adicionais da página

      app.get('/index.html', (req, res) => {
              
              
          const user = {
              
              
              name: 'zhangsan',
              age: 12
          }
          const html = `<h1>姓名:${
                
                user.name},年龄:${
                
                user.age}</h1>`;
          res.send(html);
      })
      

      vantagem

      1. 前端耗时少: como o servidor é responsável por gerar dinamicamente o conteúdo html, o navegador só precisa renderizar a página diretamente, principalmente o terminal móvel, o que economiza energia
      2. 有利于seo: como o servidor responde com conteúdo html completo, é mais fácil para os rastreadores obter informações

      deficiência

      1. 占用服务器资源: Se houver muitas solicitações, isso causará uma certa pressão de acesso no servidor
      2. 不利于前后端分离,开发效率低: Usando a renderização do lado do servidor, é impossível realizar divisão de trabalho e cooperação, especialmente para projetos com alta complexidade de front-end
    2. Modelo de desenvolvimento web com separação de front-end e back-end

      O back-end é responsável apenas por fornecer a interface da API e o front-end usa o ajax para chamar o modo de desenvolvimento da interface

      vantagem

      1. 开发体验好: O front-end se concentra na interface do usuário e o back-end se concentra na API
      2. 用户体验好: A atualização parcial da página pode ser facilmente realizada
      3. 减轻了服务端渲染的压力: Porque a página final é gerada no navegador

      deficiência

      1. 不利于SEO: Como a página html completa precisa ser emendada dinamicamente no lado do cliente, o rastreador não pode rastrear as informações válidas da página

        Solução: Usar frameworks front-end como Vue e React SSRpode resolver problemas de SEO muito bem

    3. Como escolher um modelo de desenvolvimento

      Por exemplo, sites de nível empresarial são principalmente para exibição, sem interações complicadas e exigem um bom SEO, portanto, a renderização do lado do servidor é necessária

      Semelhante ao projeto de gerenciamento de plano de fundo, a interatividade é relativamente forte e você não precisa considerar o SEO, pode usar o modo de desenvolvimento de separação de front-end e back-end

  2. Autenticação

    1. definição

      Também conhecido como "verificação de identidade" e "autenticação", é para completar a autenticação de identidade dos usuários através de determinados meios

    2. Por que a autenticação é necessária

      Para confirmar que o usuário atualmente em uso é o usuário do sistema

    3. Autenticação para diferentes modos de desenvolvimento

      1. Usos de renderização do lado do servidorSession认证机制
      2. Uso separado das extremidades dianteira e traseiraJWT认证机制
  3. Mecanismo de autenticação de sessão

    1. A ausência de estado do protocolo http

      Refere-se ao cliente 每次http请求都是独立的, não há relação direta entre várias solicitações consecutivas,服务器不会主动保留每次http请求的状态

    2. Biscoito

      1. 4kbé uma string armazenada no navegador do usuário que não excede
      2. É na forma de valor-chave
      3. Existem vários outros atributos opcionais que permitem aos usuários controlar a validade, segurança e escopo de aplicação do cookie
      4. Cookies de diferentes nomes de domínio são independentes
      5. Sempre que o cliente iniciar uma solicitação 自动, 当前域名o seguinte 所有未过期cookie será enviado ao servidor junto

      Recursos de resumo: envio automático, nome de domínio independente, limite de tempo de expiração, limite de 4 KB

    3. O papel dos cookies na autenticação de identidade

      第一次Quando o cliente solicita o servidor, o servidor 响应头envia um cookie de autenticação para o cliente por meio do formulário e o cliente salva automaticamente o cookie no navegador

      Depois disso, quando o cliente navegar 每次请求服务器, o navegador enviará automaticamente 请求头o cookie relacionado à autenticação de identidade para o servidor na forma de passagem, e o servidor poderá verificar a identidade do cliente

    4. Os cookies não são seguros

      Como os cookies são armazenados no navegador e os navegadores também fornecem APIs para ler e gravar cookies, os cookies são facilmente falsificados

      Portanto, não é recomendável que o servidor envie dados privados importantes (como informações do usuário, senhas etc.) para o navegador na forma de cookies.

    5. Princípio de funcionamento da sessão

      1. Login do cliente: envie a senha da conta
      2. O servidor verifica a senha da conta, armazena as informações do usuário após o login bem-sucedido na memória do servidor e gera a string de cookie correspondente ao mesmo tempo
      3. O servidor retorna o cookie gerado para o cliente
      4. O cliente armazena automaticamente o cookie sob o nome de domínio atual
      5. Quando o cliente inicia uma solicitação novamente, todos os cookies do nome de domínio atual são enviados ao servidor por meio do cabeçalho da solicitação
      6. O servidor procura as informações de usuário correspondentes na memória de acordo com o cookie no cabeçalho da solicitação
      7. Após a autenticação do usuário ser bem-sucedida, o servidor retorna o conteúdo da resposta específica gerada pelo usuário atual para o navegador
  4. Usando autenticação de sessão no Express

    1. Instalar middleware de sessão expressa

      npm install express-session
      
    2. Salvar dados na sessão

      const session = require("express-session");
      const express = require("express");
      
      const app = express();
      
      // 配置Session
      app.use(
      session({
              
              
          secret: "secret", // 属性值可以为任意字符串
          resave: false, // 固定写法
          saveUninitialized: true, // 固定写法
      })
      );
      
      // 配置解析application/json格式数据的内置中间件
      app.use(express.json());
      // 配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
      app.use(express.urlencoded({
              
               extended: false }));
      
      // 登陆接口
      app.post('/api/login', (req, res) => {
              
              
          console.log('res.body :>> ', res.body);
          // 判断用户信息是否正确
          if (req.body.username !== 'lan' || req.body.password !== '1234') {
              
              
              return res.send({
              
              
                  code: 500,
                  msg: '登录失败'
              })
          }
          // 存储用户信息
          req.session.user = req.body;
          req.session.isLogin = true;
      
          res.send({
              
              
              code: 200,
              msg: '登陆成功',
          })
      })
      
      app.listen(80, () => {
              
              
          console.log('express server running at http://127.0.0.1 and listening on 80')
      })
      
    3. Obter dados da sessão

      // 获取用户姓名接口
      app.get('/api/getUserName', (req, res) => {
              
              
          // 判断用户是否登陆
          if (!req.session.isLogin) {
              
              
              return res.send({
              
              
                  code: 500,
                  msg: '用户未登录'
              })
          }
          res.send({
              
              
              code: 200,
              data: req.session.user.username,
              msg: 'success'
          })
      })
      
    4. limpar sessão

      // 退出登录接口
      app.post('/api/logout', (req, res) => {
              
              
          req.session.destroy();
          res.send({
              
              
              code: 200,
              msg: '退出登录成功',
          })
      })
      
  5. Mecanismo de autenticação JWT

    1. Limitações da Autenticação de Sessão

      Apenas a autenticação de sessão 需要配合Cookiepode ser realizada. Como os cookies não suportam acesso entre domínios por padrão, quando se trata da 前端跨域请求interface de back-end, 需要做很多额外配置a autenticação de sessão só pode ser realizada

      1. Quando o front-end solicita a interface de back-end e não há problema entre domínios, é recomendável usar a autenticação de sessão
      2. Quando o front-end precisa solicitar a interface de back-end entre domínios, não é recomendável usar o mecanismo de autenticação de sessão e é recomendável usar o mecanismo de autenticação JWT
    2. O que é JWT (JSON Web Token)

      é atualmente a solução entre domínios mais popular

    3. princípio de trabalho

      1. Login do cliente enviar senha da conta
      2. Senha da conta de verificação do servidor
      3. Depois que a verificação do lado do servidor é aprovada, o objeto de informações do usuário é criptografado e uma string de token é gerada
      4. O servidor retorna o Token gerado para o cliente
      5. O cliente armazena o Token em localStorage ou sessionStorage
      6. Quando o cliente solicitar novamente, o Token é enviado ao servidor através da Autorização do cabeçalho da solicitação
      7. O servidor restaura a string de token para o objeto de informações do usuário
      8. Após a autenticação do usuário ser bem-sucedida, o servidor retorna ao navegador o conteúdo da resposta específica gerada pelo usuário atual

      Resumo: as informações do usuário são salvas no navegador do cliente na forma de string de token e o servidor autentica a identidade do usuário restaurando a forma de string de token

    4. Componentes JWT

      .Geralmente consiste em 3 partes, separadas por inglês

      1. Header(Cabeça): Partes relacionadas à segurança

      2. Payload(Payload): A parte real das informações do usuário, que é a sequência criptografada de informações do usuário

      3. Signature(Assinatura): Parte relacionada à segurança

        // 格式
        Header.Payload.Signature
        
        // 示例
        aaaaaa.bbbbbbb.cccccc
        
    5. Como usar o JWT

      1. Após o cliente receber o Token retornado pelo servidor, ele geralmente o armazena em localSotrage ou sessionStorage
      2. Depois disso, toda vez que o cliente se comunicar com o servidor, ele deve trazer essa string de token para autenticação de identidade
      3. A maneira recomendada é colocar Token no Authorizationcampo do cabeçalho da solicitação http
      Authorization: Bearer <token>
      
    6. Usando JWTs no Express

      1. Instalar

        npm install jsonwebtoken express-jwt
        
        1. jsonwebtoken: para 生成string JWT
        2. express-jwt: usado para 解析restaurar strings JWT para objetos JSON
      2. Defina a chave secreta

        Para garantir a segurança da string JWT e evitar que ela seja quebrada por outros durante a transmissão da rede, é necessário especificar uma chave secreta para 加密e解密

        1. Ao gerar a string JWT, você precisa usar a chave secreta para emparelhar as informações do usuário进行加密
        2. Ao restaurar a string JWT, você precisa usar o segredo进行解密

        A essência é uma corda

      3. Definição e uso

        1. Contanto que o middleware seja configurado com sucesso express-jwt, as informações do usuário analisadas podem ser suspensas nas req.userpropriedades
        2. req.userO conteúdo é jwt.sign()o objeto armazenado no primeiro parâmetro
      4. Código de amostra

        const express = require("express");
        const cors = require("cors");
        const multipart = require("connect-multiparty");
        
        const app = express();
        const multipartMiddleware = multipart();
        
        const jwt = require("jsonwebtoken");
        const expressJWT = require("express-jwt");
        
        app.use(cors());
        app.use(multipartMiddleware);
        
        // 配置解析application/json格式数据的内置中间件
        app.use(express.json());
        // 配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
        app.use(express.urlencoded({
                  
                   extended: false }));
        
        // 定义一个secre密钥
        const secretKey = "hello world";
        // expressJWT.expressjwt({ secret: secretKey })是用来解析Token的中间件
        // .unless({ path: [/^\/api\//] })用来指定哪些接口不需要访问权限
        app.use(
        expressJWT.expressjwt({
                  
                   secret: secretKey, algorithms: ['HS256'] }).unless({
                  
                   path: [/^\/api\//] })
        );
        
        // 用户登录接口
        app.post("/api/login", (req, res) => {
                  
                  
        const userInfo = req.body;
        // 判断用户信息是否正确
        if (userInfo.username !== "lan" || userInfo.password !== "1234") {
                  
                  
            return res.send({
                  
                  
            code: 500,
            msg: "登录失败",
            });
        }
        
        res.send({
                  
                  
            code: 200,
            // 生成JWT 3个参数分别是:用户信息对象、加密密钥、配置对象
            token: jwt.sign(
            {
                  
                  
                username: userInfo.username
            },
            secretKey,
            {
                  
                  
                expiresIn: "30s",
                algorithm: "HS256",
            }
            ),
            msg: "登陆成功",
        });
        });
        
        // 获取用户姓名接口
        app.get("/admin/getUserName", (req, res) => {
                  
                  
        res.send({
                  
                  
            code: 200,
            data: req.auth,
            msg: "success",
        });
        });
        
        app.listen(80, () => {
                  
                  
        console.log("express server running at http://127.0.0.1 and listening on 80");
        });
        
      5. Capturar erros gerados após falhas de JWT

        Ao express-jwtanalisar a Token string, se a token string enviada pelo cliente expirar ou for ilegal, um erro será reportado, afetando o funcionamento normal do projeto

        Este erro pode ser detectado e processado por meio do middleware de erro do Express

        // 错误捕获
        app.use((err, req, res, next) => {
                  
                  
            if (err.name === 'UnauthorizedEror') {
                  
                  
                return res.send({
                  
                  
                    code: 401,
                    msg: '无效的token'
                })
            }
            res.send({
                  
                  
                code: 500,
                msg: '未知错误'
            })
        })
        

おすすめ

転載: blog.csdn.net/qq_43382853/article/details/130092220