Node.js【未完成】

Node.js

ノードの導入と環境のインストール

Node.js の概要

1.Node.jsとは

Node.js® は、Chrome の V8 JavaScript エンジン上に構築された JavaScript ランタイムです。

Node.js は、Chrome V8 エンジンに基づく JavaScript ランタイム環境です。

Node.js公式Webサイトアドレス:https://nodejs.org/zh-cn/

2. Node.js の JavaScript 実行環境

画像の説明を追加してください

知らせ:

①ブラウザはJavaScriptのフロントエンド実行環境です。

②Node.jsはJavaScriptのバックエンド実行環境です。

③Node.jsではDOMやBOMなどのブラウザ組み込みAPIを呼び出すことができません。

3. Node.jsでできること

Node.js は JavaScript 実行環境として、基本的な機能と API のみを提供します。ただし、Node.js が提供する基本機能に基づいて、多くの強力なツールやフレームワークが際限なく登場しているため、Node.js を学習すると、フロントエンド プログラマーがより多くの仕事やポジションに就く資格を得ることができます。

①Expressフレームワーク(http://www.expressjs.com.cn/)をベースにWebアプリケーションを迅速に構築可能

②Electronフレームワーク(https://electronjs.org/)をベースに、クロスプラットフォームのデスクトップアプリケーションを構築可能

③restifyフレームワーク(http://restify.com/)をベースにAPIインターフェースプロジェクトを迅速に構築可能

④データベースの読み書き・操作、フロントエンド開発を支援する実用的なコマンドラインツールの作成など...

ブラウザの JavaScript ラーニング パス:

JavaScript 基本構文 + ブラウザー組み込み API (DOM + BOM) + サードパーティ ライブラリ (jQuery、アート テンプレートなど)

Node.js 学習パス:

JavaScript 基本構文 + Node.js 組み込み API モジュール (fs、path、http など) + サードパーティ API モジュール (express、mysql など)

Node.js環境のインストール

Node.js を通じて Javascript コードを実行する場合は、コンピューターに Node.js 環境がインストールされている必要があります。

インストールパッケージは、Node.js 公式 Web サイトのホームページ (https://nodejs.org/en/) にアクセスし、緑色のボタンをクリックして必要なバージョンをダウンロードし、ダブルクリックして、Node.js 公式 Web サイトのホームページから直接ダウンロードできます。 -クリックして直接インストールできます。

1. LTS バージョンと現行バージョンの違いを区別する

①LTSは長期安定版であり、安定性を追求するエンタープライズレベルのプロジェクトにはLTS版のNode.jsをインストールすることを推奨します。

②Current は新機能の早期導入バージョンであり、新しい機能を試してみたいユーザーには、Node.js の Current バージョンをインストールすることをお勧めします。ただし、現在のバージョンには隠れたバグやセキュリティ上の脆弱性が存在する可能性があるため、エンタープライズ レベルのプロジェクトで Node.js の現在のバージョンを使用することはお勧めできません。

2. インストールされているNode.jsのバージョン番号を確認する

ターミナルを開き、コマンド「node –v」を入力し、Enter キーを押して、インストールされている Node.js のバージョン番号を表示します。

Windows システムでターミナルをすばやく開く方法:

ショートカット キー (Windows ロゴ キー + R) を使用して実行パネルを開き、「cmd」と入力して Enter キーを直接押してターミナルを開きます。

3. ターミナルとは何ですか?

ターミナル (英語: Terminal) は、人間とコンピューターの対話を実現する方法として開発者向けに特別に設計されています。

資格のあるプログラマとして、コンピュータをより適切に操作し使用するために、一般的に使用されるターミナル コマンドをいくつか覚えておく必要があります。

Node.js 環境で JavaScript コードを実行する

①端末を開く

②ノードで実行するjsファイルのパスを入力

1. ターミナルのショートカットキー

Windows powershell または cmd ターミナルでは、次のショートカット キーを使用してターミナルの操作効率を向上させることができます。

①↑キーを使用して、最後に実行したコマンドを素早く見つけます。

② Tab キーを使用してパスをすばやく完成させます

③escキーを使用すると、現在入力しているコマンドを素早くクリアできます。

④clsコマンドを入力してターミナルをクリアします。

ノードFSモジュール

1. fs ファイル システム モジュールとは何ですか?

fsモジュールはNode.jsが公式に提供しているファイルを操作するためのモジュールです。ユーザーのファイル操作のニーズを満たす一連のメソッドとプロパティを提供します。

例えば:

  • fs.readFile() メソッド。指定されたファイルの内容を読み取るために使用されます。
  • fs.writeFile() メソッド。指定されたファイルにコンテンツを書き込むために使用されます。

fs モジュールを使用して JavaScript コードでファイルを操作する場合は、最初に次のようにインポートする必要があります。

const fs = require('fs')

2. 指定したファイルの内容を読み込みます

1. fs.readFile()の構文形式

fs.readFile() メソッドを使用すると、指定したファイルの内容を読み取ることができます。構文形式は次のとおりです。

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

パラメータの解釈:

  • パラメータ 1path: ファイルのパスを示す必須パラメータ、文字列。
  • パラメータ 2options: ファイルを読み取るエンコード形式を示すオプションのパラメータ。
  • パラメータ3 callback: 必須パラメータ ファイルの読み込み完了後、コールバック関数を通じて読み込み結果を取得します。

2. fs.readFile()のサンプルコード

指定されたファイルの内容を utf8 エンコード形式で読み取り、err と 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: 読み取りに失敗した後の結果です

dataStr: 読み取りに成功した後の結果

3. ファイルが正常に読み取られたかどうかを確認します。

ファイル読み取りの結果を知るために、err オブジェクトが null かどうかを判断できます。

const fs = require('fs')

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

3. 指定したファイルにコンテンツを書き込みます

1. fs.writeFile()の構文形式

fs.writeFile() メソッドを使用すると、指定したファイルにコンテンツを書き込むことができます。構文は次のとおりです。

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

パラメータの解釈:

  • パラメータ 1: 必須パラメータ。ファイルのストレージ パスを示すファイル パスの文字列を指定する必要があります。
  • パラメータ 2: 書き込む内容を示す必須パラメータ。
  • パラメータ 3: ファイルの内容を書き込む形式を示すオプションのパラメータ。デフォルト値は utf8 です。
  • パラメータ 4: 必須パラメータ、ファイル書き込み完了後のコールバック関数。

2. fs.writeFile()のサンプルコード

ファイルの内容を指定したファイル パスに書き込みます。

// 导入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. ファイルが正常に書き込まれたかどうかを確認します。

ファイル書き込みの結果を知るために、err オブジェクトが null かどうかを判断できます。

// 导入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. fs モジュールパスの動的スプライシングの問題

fs モジュールを使用してファイルを操作する場合、指定された操作パスが ./ または.../ で始まる相対パスである場合、動的パスの接続エラーが発生しやすくなります。

理由: コードの実行中、操作されるファイルのフルパスは、ノードコマンドが実行されるディレクトリから動的に接続されます。

解決策: fs モジュールを使用してファイルを操作する場合は、動的パスのスプライシングの問題を防ぐために、完全なパスを直接指定し、./ または.../ で始まる相対パスを指定しないでください。

fs.readFile(__dirname + '/files/1.txt', 'utf8', function(err, dataStr) 動的スプライシングを解決する

画像の説明を追加してください

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

ノードパスモジュール

1. パスパスモジュールとは何ですか?

pathモ​​ジュールはNode.jsが公式に提供しているパスを処理するためのモジュールです。これは、パス処理に対するユーザーのニーズを満たす一連のメソッドと属性を提供します。

例えば:

  • path.join() メソッド。複数のパスの断片を結合して完全なパス文字列にするために使用されます。
  • path.basename() メソッド。パス文字列からファイル名を解析するために使用されます。

パス モジュールを使用して JavaScript コード内のパスを処理する場合は、最初に次のようにインポートする必要があります。

const path = require('path')

2. パスの接続

1. path.join()の構文形式

path.join() メソッドを使用すると、複数のパス フラグメントを完全なパス文字列に結合できます。構文形式は次のとおりです。

path.join([...paths])

パラメータの解釈:

  • …paths <string> パスフラグメントのシーケンス
  • 戻り値: <文字列>

2. path.join() のコード例

path.join() メソッドを使用すると、複数のパスのフラグメントを完全なパス文字列に結合できます。

…/前のパスをオフセットします

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)
})

注: 将来的には、パスのスプライシングに関係するすべての操作は path.join() メソッドを使用して処理する必要があります。+ を直接使用して文字列を連結しないでください。

3. パス内のファイル名を取得します

1. path.basename()の構文形式

path.basename() メソッドを使用すると、パスの最後の部分を取得できます。このメソッドは、パス内のファイル名を取得するためによく使用されます。構文形式は次のとおりです。

path.basename(path[,ext])

パラメータの解釈:

  • path <string> 必須パラメータ、パスを表す文字列
  • ext <string> ファイル拡張子を示すオプションのパラメータ
  • 戻り値: <string> はパスの最後の部分を表します。

2. path.basename() のコード例

path.basename() メソッドを使用すると、ファイル パスからファイルの名前部分を取得できます。

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. パス内のファイル拡張子を取得します。

1. path.extname()の構文形式

path.extname() メソッドを使用すると、パスの拡張子部分を取得できます。構文形式は次のとおりです。

path.extname(path)

パラメータの解釈:

  • path <string>必須パラメータ、パスを表す文字列
  • Return: <string> 取得した拡張文字列を返します。

2. path.extname() のコード例

path.extname() メソッドを使用すると、パスの拡張子部分を取得できます。

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

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

5.時計ケース

ノードhttpモジュール

1. http モジュールとは何ですか?

httpモジュールは、Webサーバーを作成するためにNode.jsが公式に提供しているモジュールです。http モジュールが提供する http.createServer() メソッドを使用すると、通常のコンピュータを簡単に Web サーバーに変えることができ、外部の Web リソース サービスを提供できます。

http モジュールを使用して Web サーバーを作成する場合は、最初にそれをインポートする必要があります。

const http = require('http')

2. httpモジュールの役割をさらに理解する

サーバーと通常のコンピューターの違いは、IIS、Apache などの Web サーバー ソフトウェアがサーバーにインストールされていることです。これらのサーバーソフトをインストールすることで、普通のパソコンをWebサーバーに変えることができます。

Node.js では、IIS や Apache などのサードパーティ Web サーバー ソフトウェアを使用する必要はありません。Node.js が提供する http モジュールに基づいたサーバー ソフトウェアを数行の簡単なコードで簡単に手書きして、外部 Web サービスを提供できるからです。

サーバー関連の概念

1.IPアドレス

IP アドレスはインターネット上のすべてのコンピュータに固有のアドレスであるため、IP アドレスは一意です。「パソコン」を「電話機」に喩えると、「IPアドレス」は「電話番号」に相当し、相手のIPアドレスが分かるだけで、対応するパソコンとデータ通信を行うことができます。

IP アドレスの形式: 通常は「ドット 10 進数」形式 (abcd) で表され、a、b、c、および d はすべて 0 ~ 255 の 10 進整数です。例: IP アドレスをドット付き 10 進数で表現した場合 (192.168.1.1)

知らせ:

  1. インターネット上の各 Web サーバーには独自の IP アドレスがあります。たとえば、Windows ターミナルで ping www.baidu.com コマンドを実行すると、Baidu サーバーの IP アドレスを表示できます。
  2. 開発中、コンピュータはサーバーとクライアントの両方になります。テストを容易にするために、ブラウザに IP アドレス 127.0.0.1 を入力して、コンピュータにサーバーとしてアクセスできます。

2. ドメイン名とドメインネームサーバー

IP アドレスはネットワーク上のコンピュータを一意にマークできますが、IP アドレスは長い数字の文字列であり、直観的ではなく、覚えにくいため、人々は別の文字ベースのアドレス スキーム、いわゆるドメイン名 (ドメイン) を発明しました。名前).)住所.

IP アドレスとドメイン名は 1 対 1 に対応しており、この対応関係はドメイン ネーム サーバー (DNS) と呼ばれるコンピュータに保存されています。ユーザーは覚えやすいドメイン名を介して対応するサーバーにアクセスするだけでよく、対応する変換作業はドメイン名サーバーによって実装されます。したがって、ドメイン ネーム サーバーは、IP アドレスとドメイン名の間の変換サービスを提供するサーバーです。

知らせ:

  1. インターネット上のコンピュータは、IP アドレスを使用するだけで正常に動作します。しかし、ドメイン名の恩恵により、インターネットの世界はさらに便利になります。
  2. 開発およびテスト中、127.0.0.1 に対応するドメイン名は localhost ですが、これらはすべて私たちのコンピュータを表しており、使用効果に違いはありません。

3. ポート番号

コンピュータのポート番号は、現実の家の番号とまったく同じです。持ち帰りボーイは、家番号を介して、建物内の多数の部屋にテイクアウト商品を正確に届けることができます。

同様に、数百または数千の Web サービスを 1 台のコンピュータ上で実行できます。各 Web サービスは一意のポート番号に対応します。クライアントから送信されたネットワーク リクエストは、ポート番号を介して、対応する Web サービスに正確に引き渡されて処理されます。

画像の説明を追加してください

知らせ:

  1. 各ポート番号を同時に複数の Web サービスで占有することはできません。
  2. 実際のアプリケーションでは、URL のポート 80 を省略できます。

最も基本的な Web サーバーを作成する

1. Web サーバーを作成する基本的な手順

①httpモジュールをインポートする

②Webサーバーインスタンスの作成

③リクエストイベントをサーバーインスタンスにバインドし、クライアントのリクエストを監視する

④サーバーを起動する

2. ステップの作成

ステップ 1 - http モジュールをインポートする

自分のコンピュータ上に Web サーバーを作成して Web サービスを外部に提供する場合は、http モジュールをインポートする必要があります。

const http = require('http')

ステップ 2 - Web サーバー インスタンスを作成する

http.createServer() メソッドを呼び出して、Web サーバー インスタンスをすばやく作成します。

const server = http.createServer()

ステップ 3 - リクエスト イベントをサーバー インスタンスにバインドする

リクエスト イベントをサーバー インスタンスにバインドして、クライアントから送信されたネットワーク リクエストを監視します。

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

ステップ 4 - サーバーを起動する

サーバー インスタンスの .listen() メソッドを呼び出して、現在の Web サーバー インスタンスを起動します。

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. reqリクエストオブジェクト

サーバーは、クライアントのリクエストを受信する限り、server.on() を通じてサーバーにバインドされたリクエスト イベント ハンドラーを呼び出します。

イベント処理関数でクライアント関連のデータまたはプロパティにアクセスする場合は、次の方法を使用できます。

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. res 応答オブジェクト

サーバーのリクエスト イベント処理関数で、サーバー関連のデータまたはプロパティにアクセスする場合は、次のメソッドを使用できます。

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.中国語文字化け問題を解決

中国語コンテンツをクライアントに送信するために res.end() メソッドを呼び出すと、文字化けが発生します。このとき、コンテンツのエンコード形式を手動で設定する必要があります。

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')
})

異なる URL に従って異なる HTML コンテンツに応答する

1. 主要な実装手順

①リクエストされたURLアドレスを取得する

②デフォルトの応答内容を404 Not foundに設定する

③ ユーザーのリクエストが / であるか /index.html ホームページであるかを判断します

④ ユーザーが /about.html About ページをリクエストしたかどうかを判断します

⑤中国語の文字化けを防ぐためにContent-Typeレスポンスヘッダを設定する

⑥res.end()を使ってクライアントに内容を応答する

2. 動的応答コンテンツ

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')
})

ケース - 時計を実装する Web サーバー

ノードモジュラー

モジュール性の基本概念

1.1 モジュール性とは

モジュール化とは、複雑な問題を解決するときに、システムを上から下まで層ごとに複数のモジュールに分割するプロセスを指します。モジュールは、システム全体において、組み合わせ、分解、交換が可能なユニットです。

プログラミングにおけるモジュール性

プログラミングの分野におけるモジュール化とは、固定ルールに従い、大きなファイルを独立および相互依存する複数の小さなモジュールに分割することです。

コードをモジュールに分割する利点は次のとおりです。

① コードの再利用性の向上

②コードの保守性向上

③オンデマンドローディングが実現可能

1.2 モジュール仕様

モジュール仕様は、コードを分割してモジュールに結合するときに従う必要があるルールです。

例えば:

  • モジュールの参照にはどのような構文形式が使用されますか?
  • メンバーを外部に公開するためにモジュールでどのような構文形式が使用されていますか?

モジュール仕様の利点: 誰もが同じモジュール仕様に準拠してコードを作成できるため、通信コストが削減され、さまざまなモジュール間の相互呼び出しが大幅に容易になり、他人と自分自身に利益をもたらします。

Node.js のモジュール性

2.1 Node.js におけるモジュールの分類

Node.js では、モジュールはさまざまなソースに応じて 3 つのカテゴリに分類されます。

  • 組み込みモジュール (fs、path、http などの組み込みモジュールは Node.js によって公式に提供されます)
  • カスタム モジュール (ユーザーが作成したすべての .js ファイルはカスタム モジュールです)
  • サードパーティ モジュール (サードパーティによって開発されたモジュールは、正式に提供される組み込みモジュールではなく、ユーザーが作成したカスタム モジュールでもないため、使用前にダウンロードする必要があります)

2.2 モジュールのロード

強力な require() メソッドを使用すると、必要な組み込みモジュール、ユーザー定義モジュール、およびサードパーティ モジュールをロードして使用できます。例えば:

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

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

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

注: require() メソッドを使用して他のモジュールをロードすると、ロードされたモジュール内のコードが実行されます。

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



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

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

console.log(m1)


2.3 Node.js のモジュールスコープ

1. モジュールスコープとは何ですか?

関数スコープと同様に、カスタム モジュールで定義された変数、メソッド、およびその他のメンバーには、現在のモジュール内でのみアクセスできます。このモジュール レベルのアクセス制限は、モジュール スコープと呼ばれます。

2. モジュールスコープの利点

地球規模の変動する汚染の問題を防止します

const username = '张三'


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



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

2.4 モジュールスコープ内のメンバーを外部に共有する

1.モジュールオブジェクト

各 .js カスタム モジュールには、現在のモジュールに関連する情報を保存するモジュール オブジェクトがあり、次のように出力されます。

画像の説明を追加してください

2. module.exports オブジェクト

カスタム モジュールでは、 module.exports オブジェクトを使用して、モジュール内のメンバーを外部で使用するために共有できます。

外部が require() メソッドを使用してカスタム モジュールをインポートすると、取得されるのは module.exports が指すオブジェクトです。

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

module.exports.sayHello = function() {
    
    
    console.log(hello)
}
3. メンバー共有時の注意点

require() メソッドを使用してモジュールをインポートする場合、インポート結果は常に module.exports が指すオブジェクトに基づきます。

画像の説明を追加してください

4. オブジェクトをエクスポートします

module.exports という単語の記述は複雑であるため、メンバーを外部に共有するためのコードを簡略化するために、Node はエクスポート オブジェクトを提供します。デフォルトでは、exports と module.exports は同じオブジェクトを指します。最終的な共有結果は、依然として module.exports が指すオブジェクトに基づいています。

画像の説明を追加してください

console.log(exports)     /

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

console.log(exports === module.exports)    //true
5.exports と module.exports の使用における誤解

モジュールを require() するときは、常に module.exports が指すオブジェクトを取得することを常に覚えておいてください。

画像の説明を追加してください

注: 混乱を避けるために、同じモジュール内でexportsとmodule.exportsを同時に使用しないことをお勧めします。

2.5 Node.js のモジュール仕様

Node.js は、モジュールの特性とモジュール間の依存関係を指定する CommonJS モジュラー仕様に従っています。

CommonJS では次のように述べられています。

①各モジュール内では、モジュール変数が現在のモジュールを表します。

②モジュール変数はオブジェクトであり、そのexports属性(すなわちmodule.exports)が外部インターフェースです。

③モジュールをロードすると、実際にはモジュールの module.exports 属性がロードされます。require() メソッドはモジュールをロードするために使用されます。

npmとパッケージ

3.1 パッケージ

1. パッケージとは何ですか?

Node.js のサードパーティ モジュールはパッケージとも呼ばれます。

コンピュータとコンピュータが同じものを指すのと同様に、サードパーティのモジュールとパッケージも同じ概念を指しますが、名前は異なります。

2. パッケージのソース

Node.js の組み込みモジュールやカスタム モジュールとは異なり、パッケージはサードパーティの個人またはチームによって開発され、誰でも無料で使用できます。

注: Node.js のパッケージはすべて無料のオープンソースであり、料金を支払わなくても無料でダウンロードして使用できます。

3. なぜパッケージが必要なのでしょうか?

Node.js の組み込みモジュールは一部の低レベル API しか提供していないため、組み込みモジュールに基づくプロジェクト開発の効率は非常に低くなります。

パッケージは組み込みモジュールに基づいてカプセル化されており、より高度で便利な API を提供し、開発効率を大幅に向上させます。

パッケージと組み込みモジュールの関係は、jQuery と組み込みブラウザー API の関係に似ています。

4. パッケージはどこからダウンロードすればよいですか?

海外にnpm, Inc.というIT企業がありますが、この会社は世界最大の荷物共有プラットフォームであるhttps://www.npmjs.com/という非常に有名なウェブサイトを持っており、このウェブサイトから検索することができます。十分な忍耐力がある限り!

これまでに、世界中の 1,100 万人以上の開発者が、このパッケージ共有プラットフォームを通じて、私たちが使用するために 120 万個以上のパッケージを開発、共有してきました。

npm, Inc. は、https://registry.npmjs.org/ にすべてのパッケージを外部に共有するためのサーバーを提供しており、このサーバーから必要なパッケージをダウンロードできます。

知らせ:

  • https://www.npmjs.com/ Web サイトから必要なパッケージを検索します。
  • https://registry.npmjs.org/ サーバーから必要なパッケージをダウンロードします。
5. パッケージのダウンロード方法

npm, Inc. はパッケージ管理ツールを提供しており、このパッケージ管理ツールを使用すると、必要なパッケージを https://registry.npmjs.org/ サーバーからダウンロードしてローカルで使用できます。

このパッケージ管理ツールの名前は Node Package Manager (npm パッケージ管理ツールと呼ばれます) であり、このパッケージ管理ツールは Node.js インストール パッケージとともにユーザーのコンピューターにインストールされます。

ターミナルで npm -v コマンドを実行すると、コンピューターにインストールされている npm パッケージ管理ツールのバージョン番号を確認できます。

3.2npmの初体験

1. 時刻をフォーマットする従来の方法

画像の説明を追加してください

①フォーマット時間用のカスタムモジュールを作成する

②フォーマット時間の定義方法

③ゼロパディング関数の作成

④カスタムモジュールからフォーマット時間関数をエクスポート

⑤フォーマット時間のためにカスタムモジュールをインポート

⑥フォーマット時間の関数を呼び出す

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. 時間をフォーマットするための高度な方法

①npmパッケージ管理ツールを使用して、フォーマットされたタイムパッケージモーメントをプロジェクトにインストールします

②require()を使用してフォーマットされた時刻パッケージをインポートします

③時刻のフォーマットについてはmomentの公式APIドキュメントを参照してください。

const moment = require('moment')

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

console.log(dt)
3. プロジェクトにパッケージをインストールするコマンド

指定した名前のパッケージをプロジェクトにインストールする場合は、次のコマンドを実行する必要があります。

npm install 包完整的名称

上記のパッケージ化コマンドは、次の形式に短縮できます。

npm i 包完整的名称
4. 最初のパッケージ化後にはどのような追加ファイルが含まれますか?

初期パッケージ化が完了すると、プロジェクト フォルダーの下に、node_modules という追加フォルダーと構成ファイル package-lock.json が作成されます。

で:

node_modules フォルダーは、プロジェクトにインストールされているすべてのパッケージを保存するために使用されます。require() がサードパーティのパッケージをインポートする場合、このディレクトリからパッケージを検索してロードします。

package-lock.json 構成ファイルは、パッケージ名、バージョン番号、ダウンロード アドレスなど、node_modules ディレクトリ内の各パッケージのダウンロード情報を記録するために使用されます。

注: プログラマーは、node_modules または package-lock.json ファイル内のコードを手動で変更しないでください。これらは、npm パッケージ管理ツールによって自動的に保守されます。

5. 指定されたバージョンのパッケージをインストールします

デフォルトでは、npm install コマンドを使用してパッケージをインストールすると、パッケージの最新バージョンが自動的にインストールされます。特定のバージョンのパッケージをインストールする必要がある場合は、パッケージ名の後ろに @ 記号を使用して特定のバージョンを指定できます。次に例を示します。

npm i moment@2.22.2
6. パッケージのセマンティックバージョン指定

パッケージのバージョン番号は、2.24.0 のように、合計 3 桁の「ドット 10 進数」形式で定義されます。

各桁の意味は次のとおりです。

1桁目:大型版

2桁目:機能バージョン

3桁目:バグ修正バージョン

バージョン番号昇格のルール: 以前のバージョン番号が増加する限り、次のバージョン番号は 0 に戻ります。

3.3 パッケージ管理設定ファイル

npm では、package.json というパッケージ管理構成ファイルをプロジェクトのルート ディレクトリに提供する必要があると規定しています。プロジェクトに関連するいくつかの構成情報を記録するために使用されます。例えば:

  • プロジェクト名、バージョン番号、説明など。
  • プロジェクトではどのようなパッケージが使用されていますか?
  • 開発中にのみ使用されるパッケージはどれですか
  • これらのパッケージは開発および展開中に必要になります。
1. 複数人でのコラボレーションの問題

画像の説明を追加してください

プロジェクト全体のボリュームは3040万です

サードパーティパッケージのサイズは2880万です

プロジェクトのソースコードのサイズは1.6Mです

発生した問題: サードパーティのパッケージのサイズが大きすぎるため、チーム メンバーがプロジェクトのソース コードを共有するのが不便です。

解決策: 共有時にnode_modulesを削除します。

2. プロジェクトにインストールされているパッケージを記録する方法

プロジェクトのルート ディレクトリに、package.json という構成ファイルを作成します。このファイルは、プロジェクトにインストールされているパッケージを記録するために使用できます。これにより、node_modules ディレクトリを削除した後、チーム メンバー間でプロジェクトのソース コードを共有しやすくなります。

注: 今後のプロジェクト開発では、node_modules フォルダーを .gitignore 無視ファイルに必ず追加してください。

3. package.jsonを素早く作成する

npm パッケージ管理ツールには、コマンドが実行されるディレクトリに package.json パッケージ管理構成ファイルをすばやく作成するためのショートカット コマンドが用意されています。

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

知らせ:

  • 上記のコマンドは、英語のディレクトリでのみ正常に実行できます。したがって、プロジェクト フォルダーの名前は中国語ではなく英語で付ける必要があり、スペースを含めることはできません。

  • npm install コマンドを実行してパッケージをインストールすると、npm パッケージ管理ツールはパッケージの名前とバージョン番号を package.json に自動的に記録します。

4. 画像の説明を依存関係ノードに追加し、直接アップロードしてください。

画像の説明を追加してください

package.json ファイルには、npm install コマンドを使用してインストールしたパッケージを記録するために特別に使用される依存関係ノードがあります。

5. すべてのパッケージを一度にインストールします

node_modules が削除されたプロジェクトを取得した場合、プロジェクトを実行する前に、すべてのパッケージをプロジェクトにダウンロードする必要があります。

それ以外の場合は、次のようなエラーが報告されます。

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

npm install コマンド (または npm i) を実行して、すべての依存パッケージを一度にインストールできます。

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

npm install
6. パッケージをアンインストールします

npm uninstall コマンドを実行して、指定したパッケージをアンインストールできます。

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

注: npm uninstall コマンドが正常に実行されると、アンインストールされたパッケージは package.json の依存関係から自動的に削除されます。

7. devDependency ノード

一部のパッケージがプロジェクト開発段階でのみ使用され、プロジェクトがオンラインになった後は使用されない場合は、これらのパッケージを devDependency ノードに記録することをお勧めします。

同様に、開発およびプロジェクトの開始後に一部のパッケージを使用する必要がある場合は、これらのパッケージを依存関係ノードに記録することをお勧めします。

次のコマンドを使用して、パッケージを devDependency ノードに記録できます。

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

3.4 パケットのダウンロード速度が遅い問題を解決する

1. ダウンロード速度が遅いのはなぜですか?

npmを利用してパッケージをダウンロードする場合、デフォルトでは海外のhttps://registry.npmjs.org/サーバーからダウンロードすることになりますが、このときネットワークデータの伝送には長い海底光ケーブルを経由する必要があるため、パッケージのダウンロードは速度は非常に遅くなります。

さらに読む - 海底光ケーブル:

2.淘宝NPMミラーサーバー

画像の説明を追加してください

タオバオは中国にサーバーを構築し、海外の公式サーバーから国内サーバーにパッケージを同期し、中国でアウトソーシングサービスを提供しています。これにより、パッケージのダウンロード速度が大幅に向上します。

拡張機能:

ミラーリングはファイル ストレージの一種で、あるディスク上のデータは別のディスク上に同一のコピーを持ちます。これがミラーです。

3. npmのパッケージミラーソースを切り替える

パッケージのミラー ソースは、パッケージのサーバー アドレスを指します。

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

パッケージのイメージ ソースをより便利に切り替えるには、nrm ツールをインストールし、nrm が提供するターミナル コマンドを使用して、パッケージのイメージ ソースをすばやく表示して切り替えることができます。

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

3.5 パッケージの分類

npm パッケージ管理ツールを使用してダウンロードされたパッケージは、次の 2 つのカテゴリに分類されます。

  • プロジェクトパッケージ
  • グローバルパッケージ
1. プロジェクトパッケージ

プロジェクトの node_modules ディレクトリにインストールされるパッケージはプロジェクト パッケージです。

プロジェクト パッケージは、次の 2 つのカテゴリに分類されます。

  • 開発依存関係パッケージ (devDependency ノードに記録されたパッケージは開発中にのみ使用されます)

  • コア依存関係パッケージ (依存関係ノードに記録されたパッケージは、開発中およびプロジェクトがオンラインになった後に使用されます)

  • npm i 包名 -D #开发依赖包(记录到devDependencies 节点下)
    npm i 包名    #核心依赖包(被记录到 dependencies 节点下)
    
2. グローバルパッケージ

npm install コマンドを実行するときに、-g パラメーターを指定すると、パッケージはグローバル パッケージとしてインストールされます。

グローバル パッケージは、C:\Users\user directory\AppData\Roaming\npm\node_modules ディレクトリにインストールされます。

画像の説明を追加してください

知らせ:

① ツール パッケージのみをグローバルにインストールする必要があります。便利な端末コマンドが提供されるからです。

② パッケージを使用する前にグローバルにインストールする必要があるかどうかを判断するには、公式の使用説明書を参照してください。

3.i5ting_toc

i5ting_toc は、MD ドキュメントを HTML ページに変換できる小さなツールです。使用手順は次のとおりです。

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

3.6 標準パッケージ構造

パッケージの概念とダウンロードして使用する方法を理解した後、パッケージの内部構造を詳しく見てみましょう。

標準化されたパッケージとその構造は、次の 3 つの要件を満たす必要があります。

①パッケージは別のディレクトリに存在する必要があります

②パッケージの最上位ディレクトリには、パッケージ管理設定ファイルpackage.jsonが含まれている必要があります。

③package.json には、name、version、main の 3 つの属性が含まれている必要があります。それぞれ、パッケージの名前、バージョン番号、エントリを表します。

注: 上記の 3 つの要件は、標準化されたパッケージ構造が準拠する必要がある形式です。その他の制約については、次の Web サイトを参照してください。

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

3.7 独自のパッケージを開発する

1. 実装する機能

①日付のフォーマット

② HTML内の特殊文字をエスケープする

③HTML内の特殊文字を復元する

1. 実装する機能
// 导入自己的包
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. 初期化パッケージの基本構造

①パッケージのルートディレクトリにitheima-toolsフォルダを新規作成します。

②itheima-toolsフォルダ内に以下の3つのファイルを作成します。

  • package.json (パッケージ管理構成ファイル)
  • Index.js (パッケージのエントリファイル)
  • README.md (パッケージのドキュメント)
3. package.jsonを初期化する
{
    
    
    "name": "suz-tools",
    "version": "1.0.0",
    "main": "index.js",
    "description": "提供了格式化时间、HTMLEscape相关的功能",
    "keywords": [
        "dateFormat",
        "secape"
    ],
    "license": "ISC"
}

ライセンス契約の詳細については、https://www.jianshu.com/p/86251523e898 を参照してください。

4.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.index.jsでHTMLをエスケープするメソッドを定義する
function htmlEscape(htmlStr) {
    
    
    return htmlStr.replace(/<|>|"|&/g, (match) => {
    
    
        switch (match) {
    
    
            case '<':
                return '&lt;'
            case '>':
                return '&gt;'
            case '"':
                return '&quot;'
            case '&':
                return '&amp;'
        }
    })
}
6.index.jsにHTMLを復元するメソッドを定義する
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. さまざまな機能をモジュール化して分割する

①時刻をフォーマットする機能をsrc -> dateFormat.jsに分割

②HTML文字列を処理する機能をsrc→htmlEscape.jsに分割

③index.jsで、外部共有が必要なメソッドを取得するモジュールを2つインポートします。

④index.jsではmodule.exportsを使って対応するメソッドを共有します。

8. パッケージのドキュメントを作成する

パッケージのルート ディレクトリにある README.md ファイルは、パッケージの使用方法に関するドキュメントです。これにより、ユーザーの利便性のために、パッケージの使用方法をマークダウン形式で事前に記述することができます。

READMEファイルには、パッケージの機能、使用方法、注意事項等を明確に記載できれば、どのような内容を記載する必要はありません。

作成したパッケージの README.md ドキュメントには、次の 6 つの項目が含まれます。

インストール方法、インポート方法、フォーマット時間、HTML内の特殊文字のエスケープ、HTML内の特殊文字の復元、オープンソース契約

3.8 リリースパッケージ

1.npmアカウントを登録する

①https://www.npmjs.com/ Webサイトにアクセスし、サインアップボタンをクリックして登録ユーザーインターフェースに入ります。

②アカウント関連情報を入力します:フルネーム、公開メールアドレス、ユーザー名、パスワード

③「アカウント作成」ボタンをクリックしてアカウントを登録します。

④メールアドレスにログインし、認証リンクをクリックしてアカウントを認証します。

2.npmアカウントにログインします

npmアカウントの登録が完了したら、ターミナルでnpmloginコマンドを実行し、ユーザー名、パスワード、メールアドレスを順に入力するとログインに成功します。

注: npm login コマンドを実行する前に、まずパッケージのサーバー アドレスを npm の公式サーバーに切り替える必要があります。そうしないと、パッケージの公開が失敗します。

3. パッケージを npm に公開します

ターミナルをパッケージのルート ディレクトリに切り替えた後、npm public コマンドを実行して、パッケージを npm に公開します (注: パッケージ名は同じであってはなりません)。

画像の説明を追加してください

4. 公開されたパッケージを削除する

npm unpublish package name --force コマンドを実行して、公開されたパッケージを npm から削除します。

知らせ:

①npm unpublish コマンドは、72 時間以内に公開されたパッケージのみを削除できます。

②npm unpublishにより削除されたパッケージは24時間以内は再公開できません。

③パッケージを公開するときは注意して、意味のないパッケージをnpmに公開しないようにしましょう!

モジュールロード機構

4.1 キャッシュからの読み込みを優先する

モジュールは最初にロードされた後にキャッシュされます。これは、require() を複数回呼び出しても、モジュールのコードが複数回実行されることはないことも意味します。

注: 組み込みモジュール、ユーザー定義モジュール、サードパーティ モジュールのいずれであっても、最初にキャッシュからロードされるため、モジュールのロード効率が向上します。

4.2 内蔵モジュールのロード機構

組み込みモジュールは Node.js が公式に提供するモジュールであり、読み込み優先度が最も高くなります。

たとえば、require('fs') は、node_modules ディレクトリに fs という同じ名前のパッケージがある場合でも、常に組み込みの fs モジュールを返します。

4.3 カスタムモジュールのロードメカニズム

require() を使用してカスタム モジュールをロードする場合は、./ または .../ で始まるパス識別子を指定する必要があります。カスタム モジュールをロードするときに、./ や .../ などのパス識別子が指定されていない場合、ノードはそれを組み込みモジュールまたはサードパーティ モジュールとしてロードします。

同時に、require() を使用してカスタム モジュールをインポートするときに、ファイル拡張子が省略されている場合、Node.js は次のファイルを順番に読み込もうとします。

①正確なファイル名に従ってロードする

②拡張子.jsを完成させて読み込む

③.json拡張子を完成させてロードします

④ロードする.node拡張子を完成させます

⑤読み込みに失敗し、端末がエラーを報告する

4.4 サードパーティモジュールのロードメカニズム

require() に渡されたモジュール識別子が組み込みモジュールではなく、「./」または「.../」で始まらない場合、Node.js は現在のモジュールから始めて /node_modules フォルダーからロードしようとします。モジュールの親ディレクトリ サードパーティのモジュール。

対応するサードパーティ モジュールが見つからない場合は、1 レベル上の親ディレクトリに移動され、ファイル システムのルート ディレクトリまでロードされます。

たとえば、require('tools') が 'C:\Users\itheima\project\foo.js' ファイルで呼び出されると仮定すると、Node.js は次の順序で検索します。

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

② C:\Users\itheima\node_modules\tools

③ C:\Users\node_modules\tools

④ C:\node_modules\tools

4.5 モジュールとしてのディレクトリ

ロードのためにディレクトリをモジュール識別子として require() に渡す場合、ロード方法は 3 つあります。

①ロード中のディレクトリで package.json というファイルを探し、require() ロードのエントリ ポイントとして機能する main 属性を探します。

② ディレクトリに package.json ファイルが存在しない場合、またはメイン エントリが存在しないか解析できない場合、Node.js はディレクトリにindex.js ファイルをロードしようとします。

③上記の 2 つの手順が失敗した場合、Node.js はターミナルにエラー メッセージを出力し、不足しているモジュールを報告します: エラー: モジュール 'xxx' が見つかりません

急行

Express の最初の紹介

1.1 Express の概要

1.Expressとは

公式コンセプト: Express は、Node.js プラットフォームに基づいた高速、オープン、ミニマリストの Web 開発フレームワークです。

一般的な理解: Express は Node.js の組み込み http モジュールと同様に機能し、Web サーバーの作成に特に使用されます。

Express の本質: これは、Web サーバーを迅速に作成する便利な方法を提供する npm 上のサードパーティ パッケージです。

Express の中国語公式 Web サイト: http://www.expressjs.com.cn/

2. Express について詳しく知る

考えてみます: Express を使用せずに Web サーバーを作成することは可能でしょうか?

回答: はい、Node.js が提供するネイティブ http モジュールを使用できます。

考えてみます: すでに優れているのに、なぜ明るくする必要があるのでしょうか (http 組み込みモジュールがあるのに、なぜ依然として Express を使用するのでしょうか)。

回答: 組み込みの http モジュールは使用が非常に複雑で、開発効率が低くなります。Express は組み込みの http モジュールに基づいてさらにカプセル化されるため、開発効率が大幅に向上します。

考えてみます: http 組み込みモジュールと Express の間にはどのような関係があるのでしょうか?

回答: ブラウザーにおける Web API と jQuery の関係に似ています。後者は前者に基づいてさらにカプセル化されます。

3. Express でできること

フロントエンド プログラマにとって、最も一般的なサーバーは次の 2 つです。

  • Web Web サイトサーバー: 特に外部 Web ページリソースを提供するサーバー。
  • API インターフェース サーバー: API インターフェースを外部に提供するサーバー。

Express を使用すると、Web ウェブサイト サーバーや API インターフェイス サーバーを簡単かつ迅速に作成できます。

1.2 Expressの基本的な使い方

1. インストール

プロジェクトが配置されているディレクトリで、次のターミナル コマンドを実行して、Express をプロジェクトにインストールして使用します。

npm i [email protected]
2. 基本的な Web サーバーを作成する
// 导入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. GET リクエストをリッスンする

app.get() メソッドを使用すると、クライアントの GET リクエストを監視できます。具体的な構文形式は次のとおりです。

//参数1: 客户端请求URL	地址
//参数2: 请求对应的出来函数
//       req: 请求对象(包含了与请求相关的属性与方法)
//       res: 响应对象(包含了与响应相关的属性与方法)
app.get('请求URL'function(req,res) {
    
     /*处理函数*/ })
4. POSTリクエストをリッスンする

app.post() メソッドを使用すると、クライアントの POST リクエストを監視できます。具体的な構文形式は次のとおりです。

app.post('请求URL'function(req,res) {
    
     /*处理函数*/ })
5. コンテンツをクライアントに返信します

res.send() メソッドを通じて、処理されたコンテンツをクライアントに送信できます。

// 导入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. URL に含まれるクエリ パラメータを取得します。

req.query オブジェクトを介して、クライアントからサーバーにクエリ文字列の形式で送信されたパラメーターにアクセスできます。

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

7. URL 内の動的パラメータを取得する

req.params オブジェクトを通じて URL にアクセスし、次のように動的パラメーターを照合できます。

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

1.3 静的リソースのホスティング

1.express.static()

Express には、express.static() という非常に使いやすい関数が用意されています。これを使用すると、静的リソース サーバーを簡単に作成できます。たとえば、次のコードを使用して、画像、CSS ファイル、および JavaScript ファイルはパブリック ディレクトリにあります。一般に公開します。

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

これで、パブリック ディレクトリ内のすべてのファイルにアクセスできるようになります。

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

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

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

注: Express は、指定された静的ディレクトリ内のファイルを検索し、リソースへのアクセス パスを外部に提供します。

したがって、静的ファイルが保存されているディレクトリの名前は 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. 複数の静的リソース ディレクトリをホストする

複数の静的リソース ディレクトリをホストしたい場合は、express.static() 関数を複数回呼び出してください。

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

静的リソース ファイルにアクセスする場合、express.static() 関数はディレクトリが追加された順序に従って必要なファイルを検索します。

3. マウントパスプレフィックス

管理対象静的リソースのアクセス パスの前にパス プレフィックスをマウントする場合は、次の方法を使用できます。

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

これで、/public というプレフィックスが付いたアドレスを介して、パブリック ディレクトリ内のファイルにアクセスできるようになります。

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

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

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

1.4 nodemon

1. なぜノードモンを使用するのですか?

Node.js プロジェクトを作成およびデバッグするときに、プロジェクト コードを変更すると、手動で頻繁に閉じてから再起動する必要があり、非常に面倒です。

これで、プロジェクト ファイルの変更を監視できるツール nodemon (https://www.npmjs.com/package/nodemon) を使用できるようになりました。コードが変更されると、nodemon は自動的にプロジェクトを再起動します。開発とデバッグに便利です。

2.nodemonをインストールする

ターミナルで次のコマンドを実行して、nodemon をグローバルに利用可能なツールとしてインストールします。

npm install -g nodemon
3. ノードモンを使用する

Node.js に基づいて Web サイト アプリケーションを作成する場合、従来の方法は、node app.js コマンドを実行してプロジェクトを開始することです。この欠点は、コードを変更した後、プロジェクトを手動で再起動する必要があることです。

これで、node コマンドを nodemon コマンドに置き換え、nodemon app.js を使用してプロジェクトを開始できるようになりました。この利点は、コードが変更された後、nodemon によって監視されるため、プロジェクトが自動的に再起動されるという効果が得られることです。

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

エクスプレス ルーティング

2.1 ルーティングの概念

1. ルーティングとは

大まかに言えば、ルーティングはマッピング関係です。

2. Express でのルーティング

Express では、ルーティングとは、クライアント要求とサーバー処理機能の間のマッピング関係を指します。

Expressのルーティングは、リクエストの種類、リクエストのURLアドレス、処理機能の3つに分かれており、その形式は以下のとおりです。

app.METHOD(PATH,HANDLER)
4. 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. ルートマッチング処理

リクエストがサーバーに到着すると、まずルートと一致する必要があり、一致した場合にのみ、対応する処理関数が呼び出されます。

マッチングの際はルート順にマッチングを行い、リクエストタイプとリクエストURLが同時に一致した場合、Expressはリクエストを対応する関数に転送して処理します。

画像の説明を追加してください

ルートマッチングに関する注意事項:

①定義された順序に従って照合する

②リクエストタイプとリクエストされたURLが同時に一致した場合のみ、対応する処理関数が呼び出されます。

2.2 ルーティングの使用

1. 最も簡単な使い方

Express でルーティングを使用する最も簡単な方法は、アプリにルーティングをマウントすることです。サンプル コードは次のとおりです。

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. モジュラールーティング

ルートのモジュール管理を容易にするために、Express ではルートをアプリに直接マウントすることはお勧めしませんが、ルートを別のモジュールに抽出することをお勧めします。

ルーティングを別のモジュールに抽出する手順は次のとおりです。

①ルーティングモジュールに対応した.jsファイルを作成する

②express.Router()関数を呼び出してルーティングオブジェクトを作成する

③特定のルートをルーティングオブジェクトに実装する

④module.exportsを利用してルーティングオブジェクトを外部に共有する

⑤app.use()関数を使用してルーティングモジュールを登録する

3. ルーティングモジュールの作成
// 导入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. ルーティングモジュールの登録
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. ルーティングモジュールにプレフィックスを追加する

静的リソースをホストする場合の静的リソースのアクセス プレフィックスの統合マウントと同様に、ルーティング モジュールがプレフィックスを追加する方法も非常に簡単です。

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

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

エクスプレスミドルウェア

3.1 ミドルウェアの概念

1.ミドルウェアとは何ですか?

ミドルウェアとは、特にビジネス プロセスの中間処理リンクを指します。

2. 実際の例

下水を処理する場合、処理された廃水が排出基準を満たしていることを確認するために、通常 3 つの処理リンクがあります。

画像の説明を追加してください

これら 3 つの下水処理の中間処理リンクをミドルウェアと呼ぶことができます。

3. Expressミドルウェア呼び出し処理

リクエストが Express サーバーに到達すると、複数のミドルウェアを継続的に呼び出してリクエストを前処理できます。

画像の説明を追加してください

4. Expressミドルウェア形式

Express ミドルウェアは本質的には関数処理機能であり、Express ミドルウェアの形式は次のとおりです。

画像の説明を追加してください

注: ミドルウェア関数の仮パラメータ リストには、次のパラメータが含まれている必要があります。ルーティング処理関数には req と res のみが含まれます。

5. 次の関数の役割

次の機能は、複数のミドルウェアの連続呼び出しを実現するためのキーであり、フロー関係を次のミドルウェアまたはルートに転送することを意味します。

画像の説明を追加してください

3.2 Express ミドルウェアの初めての体験

1. ミドルウェア機能の定義

最も単純なミドルウェア関数は次の方法で定義できます。

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. 世界的に有効なミドルウェア

クライアントによって開始されたリクエストはすべて、サーバーに到達した後にミドルウェアをトリガーします。これは、グローバルに有効なミドルウェアと呼ばれます。

app.use (ミドルウェア関数) を呼び出すことで、グローバルに有効なミドルウェアを定義できます。サンプルコードは次のとおりです。

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. グローバルミドルウェアの簡略化された形式を定義する
//全局生效的中间件
app.use(function(req,res,next) {
    
    
	console.log('这是一个最简单的中间件函数')
	next()
})
4. ミドルウェアの役割

複数のミドルウェアが同じ req と res を共有します。この機能に基づいて、下流のミドルウェアまたはルーティングで使用できるように、上流のミドルウェアの req オブジェクトまたは res オブジェクトにカスタム属性またはメソッドを均一に追加できます。

画像の説明を追加してください

5. 複数のグローバルミドルウェアを定義する

app.use() を使用して、複数のグローバル ミドルウェアを連続して定義できます。クライアントリクエストがサーバーに到達すると、ミドルウェアによって定義された順序で呼び出されます。サンプルコードは次のとおりです。

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. ローカルで有効なミドルウェア

app.use()を使用しないミドルウェアをローカル有効ミドルウェアといい、サンプルコードは以下のとおりです。

//定义中间件函数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. 複数のローカルミドルウェアを定義する

複数のローカル ミドルウェアは、次の 2 つの同等の方法でルーティングに使用できます。

//以下两种写法是“完全等价”的,可根据自己的爱好,选择一种方式进行使用
app.get('/', mw1,mw2, function(req, res) {
    
     res.send('Home page') })
app.get('/',[ mw1,mw2], function(req, res) {
    
     res.send('Home page') })
8. ミドルウェア利用時の5つの注意点を理解する

① ルーティング前に必ずミドルウェアを登録してください

②クライアントから送信されたリクエストを複数のミドルウェアを連続して呼び出すことで処理できます。

③ミドルウェア業務コード実行後、必ずnext()関数を呼び出してください。

④コード論理の混乱を避けるため、next()関数を呼び出した後に追加のコードを記述しないでください。

⑤複数のミドルウェアを連続して呼び出すと、reqオブジェクトとresオブジェクトが複数のミドルウェア間で共有されます。

3.3 ミドルウェアの分類

誰もがミドルウェアの使用法を理解し、覚えやすくするために、Express は一般的なミドルウェアの使用法を次の 5 つの主要なカテゴリに公式に分類しています。

①アプリケーションレベルのミドルウェア

②ルーティングレベルのミドルウェア

③エラーレベルミドルウェア

④Express組み込みミドルウェア

⑤ サードパーティ製ミドルウェア

1. アプリケーションレベルのミドルウェア

app.use()、app.get()、または app.post() を通じてアプリ インスタンスにバインドされたミドルウェアは、アプリケーション レベルのミドルウェアと呼ばれます。コード例は次のとおりです。

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

//应用级别中间件(局部中间件)
app.get('/' , mw1 ,(req,res) => {
	res.send('Home page')
})
2. ルーティングレベルのミドルウェア

Express.Router() インスタンスにバインドされたミドルウェアは、ルートレベルのミドルウェアと呼ばれます。その使用方法はアプリケーションレベルのミドルウェアと何ら変わりません。ただし、アプリケーション レベルのミドルウェアはアプリ インスタンスにバインドされ、ルート レベルのミドルウェアはルーター インスタンスにバインドされます。コード例は次のとおりです。

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

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

app.use('/',router)
3. 間違ったレベルのミドルウェア

エラー レベル ミドルウェアの役割: プロジェクト全体で発生する異常なエラーを捕捉し、プロジェクトが異常にクラッシュするのを防ぐために特に使用されます。

形式: エラーレベルミドルウェアの関数処理関数には4つの仮引数が必要で、仮引数の順序は前から(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向客户端响应错误相关的内容
})

注: エラー レベルのミドルウェアは、すべてのルートの後に登録する必要があります。

エラーレベルミドルウェアの関数処理関数には4つの仮引数が必要であり、仮引数の順序は前から(err、req、res、next)となります。

注: エラー レベルのミドルウェアは、すべてのルートの後に登録する必要があります。

4. Express組み込みミドルウェア

Express 4.16.0 バージョン以降、Express には一般的に使用される 3 つのミドルウェアが組み込まれており、Express プロジェクトの開発効率とエクスペリエンスが大幅に向上しました。

① Express.static は、HTML ファイル、画像、CSS スタイルなどの静的リソースを迅速にホストする組み込みミドルウェアです (互換性はありません)。

② Express.json はリクエスト本文データを JSON 形式で解析します (互換性あり、バージョン 4.16.0 以降でのみ利用可能)

③ Express.urlencoded は、URL エンコード形式でリクエスト本文データを解析します (互換性があり、バージョン 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. サードパーティのミドルウェア

Expressに正式に組み込まれているわけではなく、サードパーティミドルウェアと呼ばれるサードパーティが開発したミドルウェアです。プロジェクトでは、サードパーティのミドルウェアをオンデマンドでダウンロードして構成できるため、プロジェクトの開発効率が向上します。

例: [email protected] より前のバージョンでは、リクエスト本文データの解析にサードパーティのミドルウェアの本文パーサーがよく使用されていました。使用手順は次のとおりです。

①npm install body-parserを実行してミドルウェアをインストールします。

②requireを使用してミドルウェアをインポートする

③app.use()を呼び出してミドルウェアの登録と利用を行う

注: Express の組み込みの Express.urlencoded ミドルウェアは、サードパーティのミドルウェアのボディ パーサーに基づいてさらにカプセル化されています。

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 カスタムミドルウェア

1. 要件の説明と実装手順

Express.urlencoded に似たミドルウェアを手動でシミュレートし、POST 経由でサーバーに送信されたフォーム データを解析します。

実装手順:

①ミドルウェアの定義

②reqのデータイベントを聞く

③reqの終了イベントを聞く

④クエリ文字列モジュールを使用してリクエストボディデータを解析する

⑤解析したデータオブジェクトをreq.bodyとしてマウントする

⑥カスタムミドルウェアをモジュールにカプセル化

2. ミドルウェアを定義する

app.use() を使用して、グローバルに効果的なミドルウェアを定義します。コードは次のとおりです。

app.use(function(req,res,next) {
	//中间件的业务逻辑
})
3. req のデータイベントをリッスンします

ミドルウェアでは、クライアントからサーバーに送信されたデータを取得するために、req オブジェクトのデータ イベントをリッスンする必要があります。

データの量が大きすぎて一度に送信できない場合、クライアントはデータを切り取ってバッチでサーバーに送信します。したがって、データ イベントは複数回トリガーされる可能性があり、データ イベントがトリガーされるたびに、取得されるデータは完全なデータの一部にすぎず、受信したデータを手動で結合する必要があります。

//定义变量,用来存储客户端发送过来的请求体数据
let str = ''
//监听 req 的 data 事件(客户端发送过来的请求体数据)
req.on('data',(chunk) => {
    
    
	//拼接请求体数据,隐式转换为字符串
	str += chunk
})
4. req の終了イベントを聞く

リクエストボディのデータを受信すると、req の終了イベントが自動的にトリガーされます。

したがって、req の終了イベントで完全なリクエスト本文データを取得して処理できます。サンプルコードは次のとおりです。

//监听req对象的end时间(请求体发送完毕后自动触发)
req.on('end',() => {
    
    
	//打印完整的请求体数据
	console.log(str)
	//T0D0:把字符串格式的请求体数据,解析成对象格式
})
5.クエリ文字列モジュールを使用してリクエスト本文データを解析します。

Node.js には、クエリ文字列の処理に特別に使用されるクエリ文字列モジュールが組み込まれています。このモジュールが提供する parse() 関数を使用すると、クエリ文字列をオブジェクト形式に簡単に解析できます。サンプルコードは次のとおりです。

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

//调用qs.parse()方法,把查询字符串解析为对象
const body = qs.parse(str)
6. 解析されたデータ オブジェクトを req.body としてマウントします。

上流のミドルウェアと下流のミドルウェアおよびルーティングは、同じ req と res を共有します。したがって、解析されたデータを req のカスタム属性としてマウントし、ダウンストリームで使用できるように req.body という名前を付けることができます。サンプルコードは次のとおりです。

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

7. カスタムミドルウェアをモジュールにカプセル化する

コード構造を最適化するために、カスタム ミドルウェア関数を独立したモジュールにカプセル化できます。サンプル コードは次のとおりです。

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

Express を使用してインターフェイスを作成する

4.1 基本サーバーの作成

const express = require('express')

const app = express()

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

4.2 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 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 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 }))

注: リクエスト本文のデータを URL エンコード形式で取得したい場合は、ミドルウェア app.use(express.urlencoded({ extend: false })) を設定する必要があります。

4.5 CORS クロスドメイン リソース共有

1. インターフェースのクロスドメインの問題

先ほど作成した GET インターフェイスと POST インターフェイスには、クロスドメイン要求をサポートしていないという重大な問題があります。

インターフェイスのクロスドメイン問題を解決するには、主に 2 つの解決策があります。

① CORS (主流ソリューション、推奨)

② JSONP (欠陥解決策: GET リクエストのみをサポート)

2. CORS ミドルウェアを使用してクロスドメインの問題を解決する

cors は、Express 用のサードパーティ ミドルウェアです。cors ミドルウェアをインストールして構成すると、クロスドメインの問題を簡単に解決できます。

利用手順は以下の3ステップに分かれます。

①npm install corsを実行してミドルウェアをインストールします。

②const cors = require('cors')を使用してミドルウェアをインポートします

③ルーティング前に app.use(cors()) を呼び出してミドルウェアを設定する

3. CORSとは何ですか

CORS (Cross-Origin Resource Sharing、クロスオリジン リソース共有) は、一連の HTTP 応答ヘッダーで構成されており、これらの HTTP 応答ヘッダーによって、ブラウザーがフロントエンド JS コードによるドメイン間でのリソースの取得を防止するかどうかが決まります。

ブラウザーの同一オリジン セキュリティ ポリシーにより、デフォルトで Web ページからリソースへの「クロスドメイン」アクセスが禁止されます。ただし、インターフェイス サーバーが CORS 関連の HTTP 応答ヘッダーを使用して構成されている場合は、ブラウザ側のクロスドメイン アクセス制限を解除できます。

画像の説明を追加してください

4. CORS に関する注意事項

①CORSは主にサーバー側で設定します。クライアント ブラウザーは、CORS 対応インターフェイスを要求するために追加の構成を行う必要はありません。

②CORSはブラウザ互換性があります。通常、CORS が有効になっているサーバー インターフェイスにアクセスできるのは、XMLHttpRequest Level2 をサポートするブラウザーのみです (例: IE10+、Chrome4+、FireFox3.5+)。

5. CORS 応答ヘッダー - Access-Control-Allow-Origin

応答ヘッダーには Access-Control-Allow-Origin フィールドを含めることができます。その構文は次のとおりです。

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

このうち、origin パラメーターの値は、リソースへのアクセスを許可する外部ドメイン URL を指定します。

たとえば、次のフィールド値は http://itcast.cn からのリクエストのみを許可します。

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

Access-Control-Allow-Origin フィールドの値がワイルドカード * として指定されている場合、任意のドメインからのリクエストが許可されることを意味します。サンプル コードは次のとおりです。

res.setHeader('Access-Control-Allow-Origin','*')
6. CORS 応答ヘッダー - Access-Control-Allow-Headers

デフォルトでは、CORS はクライアントが次の 9 つの要求ヘッダーをサーバーに送信することのみをサポートします。

Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width、Content-Type (値は text/plain、multipart/form-data、application/x-www- に限定されます) form-urlencoded の 3 つのうち 1 つ)

クライアントが追加のリクエスト ヘッダー情報をサーバーに送信する場合、追加のリクエスト ヘッダーは Access-Control-Allow-Headers を通じてサーバー側で宣言する必要があります。そうしないと、リクエストは失敗します。

//允许客户端额外向服务器发送Content-Type请求头和X-Custom-Header请求头
//注意:多个请求头之间使用英文的逗号进行分割
res.setHeader('Access-Control-Allow-Header','Content-Type,X-Custom-Header')
7. CORS 応答ヘッダー - Access-Control-Allow-Methods

デフォルトでは、CORS はクライアントによって開始された GET、POST、および HEAD リクエストのみをサポートします。

クライアントが PUT、DELETE などを通じてサーバー リソースをリクエストしたい場合は、サーバー側の Access-Control-Alow-Methods を通じて実際のリクエストに許可される HTTP メソッドを指定する必要があります。

サンプルコードは次のとおりです。


8. CORS リクエストの分類

クライアントが CORS インターフェイスを要求すると、CORS 要求は要求メソッドと要求ヘッダーに基づいて次の 2 つのカテゴリに分類できます。

①簡単なお願い

②プリフライトリクエスト

9. 簡単なリクエスト

次の 2 つの条件を同時に満たすリクエストは、単純なリクエストです。

①リクエストメソッド:GET、POST、HEADのいずれか

② HTTP ヘッダー情報は次のフィールドを超えない: カスタム ヘッダー フィールドなし、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width、Content-Type (値アプリケーション/x の 3 つだけ) -www-form-urlencoded、multipart/form-data、text/plain)

10. プリフライトリクエスト

リクエストが次の条件のいずれかを満たしている限り、プリフライト リクエストが必要です。

①リクエストメソッドがGET、POST、HEAD以外のリクエストメソッドタイプである。

② リクエストヘッダーにカスタムヘッダーフィールドが含まれる

③application/json形式のデータをサーバーに送信

ブラウザがサーバーと正式に通信する前に、ブラウザはまずプリフライトの OPTION リクエストを送信して、サーバーが実際のリクエストを許可するかどうかを知るため、この OPTION リクエストは「プリフライト リクエスト」と呼ばれます。サーバーがプリフライト リクエストに正常に応答した後、実際のリクエストを送信し、実際のデータを伝送します。

11. 単純なリクエストとプリフライトリクエストの違い

単純なリクエストの特徴: クライアントとサーバー間で発生するリクエストは 1 つだけです。

プリフライト リクエストの特徴: クライアントとサーバーの間で 2 つのリクエストが発生し、OPTION プリフライト リクエストが成功するまで実際のリクエストは開始されません。

4.6 JSONPインターフェース

1. JSONP の概念と特性を確認する

コンセプト: ブラウザサイドパス

特徴:

①JSONP は XMLHttpRequest オブジェクトを使用しないため、実際の Ajax リクエストではありません。

②JSONPはGETリクエストのみをサポートしており、POST、PUT、DELETEなどのリクエストはサポートしていません。

2. JSONPインターフェース作成時の注意点

CORS クロスドメイン リソース共有がプロジェクトで構成されている場合、競合を防ぐために、CORS ミドルウェアを構成する前に JSONP インターフェイスを宣言する必要があります。それ以外の場合、JSONP インターフェイスは CORS が有効になったインターフェイスとして処理されます。サンプルコードは次のとおりです。


3. JSONPインターフェースを実装する手順

①クライアントから送信されたコールバック関数名を取得する

②クライアントに送信するデータをJSONP形式で取得する

③ 最初の 2 つのステップで取得したデータに基づいて、関数呼び出しの文字列を結合します。

④前ステップで結合した文字列をクライアントに応答する

4. JSONPインターフェースを実装するための特定のコード

5. jQuery を使用して Web ページで JSONP リクエストを開始する

$.ajax() 関数を呼び出して、JSONP リクエストを開始するための JSONP 構成オプションを提供します。サンプル コードは次のとおりです。


データベースとアイデンティティ認証

データベースの基本概念

1.1 データベースとは

データベースは、データを整理、保存、管理するために使用される倉庫です。

今の世界はインターネットの世界であり、たくさんのデータが溢れています。旅行記録、消費記録、閲覧したWebページ、送信したメッセージなど、データソースは数多くあります。テキスト形式のデータだけでなく、画像や音楽、音声などもすべてデータです。

インターネットの世界ではデータの管理を容易にするためにデータベース管理システム(略称:データベース)という概念があります。ユーザーは、データベース内のデータの追加、クエリ、更新、削除などの操作を実行できます。

1.2 一般的なデータベースと分類

市場にはさまざまな種類のデータベースがあり、最も一般的なデータベースは次のとおりです。

  • MySQL データベース (現在最も広く使用され、人気のあるオープンソースの無料データベース、コミュニティ + エンタープライズ)
  • Oracleデータベース(有料)
  • SQL Serverデータベース(有料)
  • Mongodb データベース (コミュニティ + エンタープライズ)

このうち、MySQL、Oracle、SQL Server は従来のデータベース (リレーショナル データベース、SQL データベースとも呼ばれます) であり、これら 3 つは同じ設計コンセプトで同様の使用法を持っています。

Mongodb は、従来のデータベースの欠点をある程度補う、新しいタイプのデータベース (非リレーショナル データベースまたは NoSQL データベースとも呼ばれます) です。

1.3 従来のデータベースのデータ組織構造

データ組織構造: データが保存される構造を指します。

従来のデータベースのデータ組織構造は、Excel のデータ組織構造と似ています。

したがって、Excel と比較して、従来のデータベースのデータ構成構造を理解し、学習することができます。

1. Excelデータの構成構造

各 Excel のデータ構成構造は、ワークブック、ワークシート、データ行、列の 4 つの部分で構成されます。

①Excel全体をブックと呼びます

②ユーザーとブックはワークシートです

③ユーザーワークシートにはデータが3行あります

④データの各行は6列の情報で構成されています

⑤情報の各列には対応するデータ型があります。

2. 従来のデータベースのデータ組織構造

従来のデータベースでは、データの組織構造はデータベース、テーブル、行、フィールドの 4 つの部分に分割されます。

① データベースは Excel ブックに似ています

② データテーブルは Excel のワークシートに似ています

③ データ行は Excel のデータの各行と同様です

④ フィールドは Excel の列に似ています

⑤ 各フィールドには対応するデータ型があります。

3. 実際の開発におけるライブラリ、テーブル、行、フィールドの関係

①実際のプロジェクト開発では、各プロジェクトが独立したデータベースに対応するのが一般的です。

② 異なるデータはデータベースの異なるテーブルに格納する必要があります。たとえば、ユーザー データは users テーブルに格納され、書籍データはbooks テーブルに格納されます。

③各テーブルに格納される具体的な情報はフィールドによって決まります。たとえば、users テーブルの場合は、id、ユーザー名、パスワードの 3 つのフィールドを設計できます。

④表中の行はそれぞれの具体的なデータを表します。

MySQL のインストールと構成

2.1 どの MySQL 関連ソフトウェアをインストールする必要があるかを理解する

開発者は、開発ニーズを満たすために MySQL Server と MySQL Workbench をインストールするだけで済みます。

  • MySQL サーバー: データ ストレージとサービスを提供するために特別に設計されたソフトウェア。
  • MySQL Workbench: MySQL Server に保存されているデータを簡単に操作できる視覚的な MySQL 管理ツール。

2.2 Mac環境へのMySQLのインストール

Mac 環境に MySQL をインストールするプロセスは、Windows 環境の手順よりもはるかに簡単です。

①まず mysql-8.0.19-macos10.15-x86_64.dmg インストール パッケージを実行して MySQL Server を Mac システムにインストールします

②mysql-workbench-community-8.0.19-macos-x86_64.dmg インストール パッケージを実行して、ビジュアル MySQL Workbench ツールを Mac システムにインストールします

特定のインストール チュートリアルについては、「マテリアル」→「MySQL for Mac」→「インストール チュートリアル - Mac システムに MySql をインストールする」→「README.md」を参照してください。

2.3 Windows環境へのMySQLのインストール

Windows 環境に MySQL をインストールするには、mysql-installer-community-8.0.19.0.msi インストール パッケージを実行して、MySQL Server と MySQL Workbench をコンピュータに一度にインストールするだけです。

特定のインストール チュートリアルについては、「マテリアル」→「MySQL for Windows」→「インストール チュートリアル - Windows システムへの MySql のインストール」→「README.md」を参照してください。

MySQLの基本的な使い方

3.1 MySQL Workbench を使用してデータベースを管理する

1. データベースに接続する

画像の説明を追加してください

2. メインインターフェイスのコンポーネントを理解する

画像の説明を追加してください

3. データベースの作成

画像の説明を追加してください

4. データテーブルの作成

画像の説明を追加してください

DataType データ型:

① int 整数

② varchar(len)文字列

③ tinyint(1) ブール値

フィールドの特別な識別:

① PK(Primary Key) 主キーと一意の識別子

② NN (Not Null) 値を空にすることはできません

③UQ(Unique)値がユニークである

④ AI(オートインクリメント)値が自動的に増加します

5. テーブルにデータを書き込む

画像の説明を追加してください

3.2 SQL を使用してデータベースを管理する

1.SQLとは何ですか

SQL (英語の正式名: Structured Query Language) は、構造化クエリ言語であり、データベースへのアクセスと処理に特に使用されるプログラミング言語です。これにより、データベース内のデータをプログラミングの形式で操作できるようになります。

3 つの重要なポイント:

①SQLはデータベースプログラミング言語です

②SQL言語で書かれたコードをSQL文といいます

③SQL言語はリレーショナルデータベース(MySQL、Oracle、SQL Serverなど)でのみ使用できます。非リレーショナル データベース (Mongodb など) は SQL 言語をサポートしません。

2. SQL でできること

① データベースのデータをクエリする

② データベースに新しいデータを挿入します

③データベース内のデータを更新する

④データベースからデータを削除する

⑤ 新しいデータベースを作成できます

⑥データベースに新規テーブルを作成可能

⑦ データベースにストアドプロシージャやビューを作成可能

⑧etc…

3. SQL の学習目標

データ テーブルから SQL を使用する方法を習得することに重点を置きます。

データのクエリ(select)、データの挿入(insert into)、データの更新(update)、データの削除(delete)

マスターする必要がある追加の 4 つの SQL 構文:

where 条件、および and or 演算子、ソートによる順序付け、count(*) 関数

3.3 SQL SELECT ステートメント

1. 文法

SELECT ステートメントは、テーブルのデータをクエリするために使用されます。実行結果は結果テーブル (結果セットと呼ばれます) に保存されます。構文形式は次のとおりです。


注: SQL ステートメント内のキーワードでは大文字と小文字が区別されません。SELECT は select と同等、FROM は from と同等です。

2. SELECT * 例

users テーブルからすべての列を選択したいと考えています。記号 * を使用して列名を置き換えることができます。例は次のとおりです:

画像の説明を追加してください

3. SELECTカラム名の例

「username」および「password」という名前の列の内容を (「users」という名前のデータベース テーブルから) 取得するには、次の SELECT ステートメントを使用します。

画像の説明を追加してください

3.4 SQL INSERT INTO 文

1. 文法

INSERT INTO ステートメントは、データ テーブルに新しいデータ行を挿入するために使用されます。構文形式は次のとおりです。


2. INSERT INTO の例

ユーザー名 tony stark およびパスワード 098123 のユーザー データを users テーブルに挿入します。例は次のとおりです。


3.5 SQL UPDATE文

1. 文法

Update ステートメントは、テーブル内のデータを変更するために使用されます。構文形式は次のとおりです。


2. UPDATE の例 - 行内の列を更新します

ユーザー テーブル内の ID 7 のユーザーのパスワードを 888888 に更新します。例は次のとおりです。


3. UPDATE の例 - 複数の列を連続して更新します。

ユーザー テーブルの ID 2 のユーザー パスワードとユーザー ステータスをそれぞれ admin123 と 1 に更新します。例は次のとおりです。


3.6 SQL DELETE 文

1. 文法

DELETE ステートメントは、テーブルから行を削除するために使用されます。構文形式は次のとおりです。


2. 削除の例

ユーザー テーブルから、ID 4 のユーザーを削除します。例は次のとおりです。


3.7 SQL WHERE 句

1. 文法

WHERE 句は、選択基準を制限するために使用されます。SELECT、UPDATE、および DELETE ステートメントでは、WHERE 句を使用して選択基準を制限できます。


2. WHERE句で使用できる演算子

次の演算子を WHERE 句で使用して、選択基準を制限できます。 次の演算子を WHERE 句で使用して、選択基準を制限できます。

画像の説明を追加してください

注: SQL の一部のバージョンでは、演算子 <> を != として記述することができます。

3. WHERE句の例

WHERE 句を使用して SELECT クエリ条件を制限できます。


3.8 SQL の AND 演算子と OR 演算子

1. 文法

AND と OR は、WHERE サブステートメント内の 2 つ以上の条件を結合します。

AND は、複数の条件が同時に満たされる必要があることを意味します。これは、JavaScript の && 演算子 (if (a !== 10 && a !== 20) など) に相当します。

OR は、いずれか 1 つの条件が満たされる限り、if(a !== 10 || a !== 20) などの JavaScript の || 演算子と同等であることを意味します。

2. AND演算子の例

ステータス 0 および ID が 3 未満のすべてのユーザーを表示するには、AND を使用します。


3. OR演算子の例

ステータス 1 またはユーザー名 zs を持つすべてのユーザーを表示するには、OR を使用します。


3.9 SQL ORDER BY 句

1. 文法

ORDER BY ステートメントは、指定された列に基づいて結果セットを並べ替えるために使用されます。

ORDER BY ステートメントは、デフォルトでレコードを昇順に並べ替えます。

レコードを降順に並べ替える場合は、DESC キーワードを使用できます。

2. ORDER BY 句 - 昇順

users テーブルのデータをステータス フィールドに従って昇順に並べ替えます。例は次のとおりです。


3. ORDER BY 句 – 降順で並べ替えます

users テーブルのデータを id フィールドに従って降順に並べ替えます。例は次のとおりです。


4. ORDER BY 句 – 複数の並べ替え

users テーブルのデータは、まずステータス フィールドに従って降順に並べ替えられ、次にユーザー名のアルファベット順に従って昇順に並べ替えられます。例は次のとおりです。


3.10 SQL COUNT(*) 関数

1. 文法

COUNT(*) 関数は、クエリ結果のデータ項目の合計数を返すために使用されます。構文形式は次のとおりです。


2. COUNT(*)の例

users テーブル内のステータス 0 のデータ項目の総数をクエリします。


3. AS を使用して列の別名を設定する

クエリされた列名の別名を設定する場合は、AS キーワードを使用できます。例は次のとおりです。


プロジェクト内でMySQLを操作する

4.1 プロジェクト内でデータベースを操作する手順

①MySQLデータベースを動作させるサードパーティ製モジュール(mysql)をインストールする

②mysqlモジュール経由でMySQLデータベースに接続します

③mysqlモジュールを介してSQL文を実行する

4.2 mysql モジュールのインストールと構成

1.mysqlモジュールをインストールする

mysql モジュールは、npm でホストされるサードパーティ モジュールです。Node.js プロジェクトで MySQL データベースに接続して操作する機能を提供します。

プロジェクトで使用する場合は、まず次のコマンドを実行して、mysql をプロジェクトの依存関係パッケージとしてインストールする必要があります。

npm install mysql
2.mysqlモジュールを設定する

mysql モジュールを使用して MySQL データベースを操作する前に、まず必要に応じて mysql モジュールを構成する必要があります。主な構成手順は次のとおりです。


3. mysql モジュールが正常に動作するかどうかをテストする

db.query() 関数を呼び出し、実行する SQL ステートメントを指定し、コールバック関数を通じて実行結果を取得します。


4.3 mysql モジュールを使用して MySQL データベースを操作する

1. データのクエリ

users テーブル内のすべてのデータをクエリします。


2. データを挿入する

ユーザー テーブルに新しいデータを追加します。ユーザー名は Spider-Man、パスワードは pcc321 です。サンプルコードは次のとおりです。


3. データを挿入する便利な方法

テーブルにデータを追加するときに、データ オブジェクトの各属性がデータ テーブルのフィールドに対応している場合は、次の方法でデータをすばやく挿入できます。


4. データの更新

次の方法でテーブル内のデータを更新できます。


5. 便利なデータ更新方法

テーブル データを更新するときに、データ オブジェクトの各属性がデータ テーブルのフィールドに対応している場合、次の方法でテーブル データを迅速に更新できます。


6. データの削除

データを削除する場合は、id などの一意の識別子に基づいて、該当するデータを削除することをお勧めします。例は次のとおりです。


7. 削除のマークを付ける

DELETE ステートメントを使用すると、実際にはテーブルからデータが削除されます。安全を期すために、マーク削除を使用して削除アクションをシミュレートすることをお勧めします。

いわゆるマーク削除とは、テーブル内のステータスと同様のステータス フィールドを設定して、現在のデータが削除されたかどうかをマークすることです。

ユーザーが削除アクションを実行するとき、DELETE ステートメントを実行してデータを削除するのではなく、UPDATE ステートメントを実行して、このデータに対応するステータス フィールドを削除済みとしてマークします。


フロントエンドとバックエンドの ID 認証

5.1 Web開発モデル

現在、主流の Web 開発モデルは次の 2 つです。

①サーバーサイドレンダリングに基づく従来のWeb開発モデル

②フロントエンドとバックエンドの分離に基づく新たなWeb開発モデル

1. サーバーサイドレンダリング Web 開発モデル

サーバー側レンダリングの概念: サーバーからクライアントに送信される HTML ページは、サーバー上で文字列を連結することによって動的に生成されます。したがって、クライアントは、Ajax などのテクノロジを使用して追加のページ データを要求する必要はありません。コード例は次のとおりです。


2. サーバーサイドレンダリングの長所と短所

アドバンテージ:

①フロントエンドの時間が短縮される。サーバー側は HTML コンテンツを動的に生成する役割を担うため、ブラウザーはページを直接レンダリングするだけで済みます。特にモバイル版はさらに省電力です。

②SEOに有利。サーバーは完全な HTML ページ コンテンツに応答するため、クローラーがクロールして情報を取得しやすくなり、SEO にさらに役立ちます。

欠点:

① サーバー側のリソースを占有します。つまり、サーバーは HTML ページのコンテンツの結合を完了しますが、リクエストが多数ある場合は、サーバーにある程度のアクセス圧力がかかります。

②フロントエンドとバックエンドの分離がうまくいかず、開発効率が低い。サーバーサイド レンダリングを使用すると、特にフロントエンドの複雑性が高いプロジェクトの場合、分業や協力が不可能になり、効率的なプロジェクト開発にはつながりません。

3. フロントエンドとバックエンドを分離した Web 開発モデル

フロントエンドとバックエンドの分離の概念: フロントエンドとバックエンドの分離の開発モデルは、Ajaxテクノロジの広範なアプリケーションに依存しています つまり、フロントエンドとバックエンドが分離されたWeb開発モデルとは、バックエンドはAPIインターフェースの提供のみを担当し、フロントエンドはAjaxを利用してインターフェースを呼び出す開発モデルです。

4. フロントエンドとバックエンドの分離のメリットとデメリット

アドバンテージ:

① **優れた開発経験。**フロントエンドは UI ページの開発に重点を置き、バックエンドは API の開発に重点を置き、フロントエンドにはより多くのオプションがあります。

② **優れたユーザーエクスペリエンス。**Ajax テクノロジーの広範な適用により、ユーザー エクスペリエンスが大幅に向上し、ページの部分更新を簡単に実現できます。

③ **サーバー側のレンダリング負荷を軽減します。**ページは最終的に各ユーザーのブラウザで生成されるためです。

欠点:

①SEOに有利ではない**完全な HTML ページをクライアント上で動的に結合する必要があるため、クローラーはページの有効な情報をクロールできません。(解決策: Vue や React などのフロントエンド フレームワークのSSR (サーバー サイド レンダー) テクノロジーを使用すると、SEO の問題をうまく解決できます。)

5. Web 開発モデルの選択方法

ビジネス シナリオについて話さずに、使用する開発モデルを盲目的に選択するのは不正な行為です。

lたとえば、複雑なインタラクションを行わずに表示することが主な機能であり、優れた SEO が必要なエンタープライズ レベルの Web サイトでは、サーバー側レンダリングを使用する必要があります。

l 高度にインタラクティブで SEO を考慮する必要のないバックエンド管理プロジェクトと同様に、フロントエンドとバックエンドを分離する開発モデルを使用できます。

また、具体的な開発モデルは絶対的なものではなく、ホームページの表示速度フロントエンドとバックエンド分離による開発効率の両方を考慮して、Webサイトによっては、フロントエンドとバックエンドが分離された画面サーバー側レンダリング + 他のページ。

5.2 ID認証

1.本人認証とは何ですか?

本人認証(Authentication) は、「本人確認」や「認証」とも呼ばれ、特定の手段によるユーザーの本人確認の完了を指します

  • ID 認証は、高速鉄道の切符の認証、携帯電話のパスワードや指紋によるロック解除、Alipay や WeChat の支払いパスワードなど、日常生活のあらゆるところで見られます。
  • Web 開発では、主要な Web サイトの携帯電話認証コード ログイン電子メール パスワード ログインQR コード ログインなどのユーザー ID 認証も関係します
2. 本人認証が必要な理由

ID 認証の目的は、現在特定の ID を主張しているユーザーが本当にそのユーザーであることを確認することです。たとえば、速達便を受け取りに宅配業者に行った場合、その速達便が自分のものであることをどのように証明しますか。

インターネット プロジェクトの開発において、ユーザーの身元をどのように認証するかは、徹底的に議論する価値のある問題です。たとえば、ウェブサイトに「ジャック・マーの入金額」が「馬化騰の口座」と誤って表示されないようにするにはどうすればよいでしょうか。

3. さまざまな開発モードでの ID 認証

サーバー側レンダリングとフロントエンドとバックエンドの分離という 2 つの開発モードには、異なる認証スキームがあります。

①サーバーサイドレンダリングにはセッション 認証メカニズムを使用することをお勧めします。

② フロントエンドとバックエンドの分離にはJWT 認証機構を使用することを推奨します。

5.3 セッション認証メカニズム

1. HTTP プロトコルのステートレスな性質

HTTP プロトコルのステートレスな性質を理解することは、セッション認証メカニズムについてさらに学ぶために必要な前提条件です。

HTTP プロトコルのステートレスな性質は、クライアントからの HTTP リクエストが独立しており、連続する複数のリクエスト間に直接の関係がなく、サーバーが各HTTPリクエストのステータスを積極的に保持しないことを意味します。

画像の説明を追加してください

2. HTTP のステートレス制限を突破する方法

スーパーマーケットの場合、レジ担当者が会計時に VIP ユーザーに割引を提供しやすくするために、スーパーマーケットは各 VIP ユーザーに会員カードを発行できます。

画像の説明を追加してください

注: Web 開発における会員カード ID 認証の専門用語はCookieです。

3. クッキーとは何ですか?

Cookie は、ユーザーのブラウザに保存される 4 KB以下 の文字列です。これは、名前 (Name)、値 (Value)、および Cookie の有効期間、セキュリティ、および使用範囲を制御するために使用されるその他のいくつかのオプションの属性で構成されます。

異なるドメイン名にある Cookie は独立しているため、クライアントがリクエストを開始すると、現在のドメイン名にある有効期限が切れていないすべてのCookie が自動的にサーバーに送信されます。

Cookie の主な特徴は次のとおりです。

①自動送信

②ドメイン名が独立している

③有効期限

④4KB制限

4. ID認証におけるCookieの役割

クライアントが初めてサーバーを要求すると、サーバーはID 認証 Cookie を応答ヘッダーの形式でクライアントに送信し、クライアントはその Cookie をブラウザーに自動的に保存します。

その後、クライアントのブラウザがサーバーをリクエストするたびに、ブラウザはID 認証関連の Cookie をリクエスト ヘッダーの形式でサーバーに自動的に送信し、サーバーはクライアントの ID を確認できます。
画像の説明を追加してください

5. Cookie は安全ではありません

Cookie はブラウザに保存され、ブラウザは Cookie の読み取りと書き込み のための API も提供するため、Cookie は 簡単に偽造され、安全ではありません。したがって、サーバーが重要な個人データを Cookie の形式でブラウザに送信することはお勧めできません。

画像の説明を追加してください

注: 重要な個人データを保存するためにCookie を使用しないでください。たとえば、ユーザーの身元情報やパスワードなどです。

6.本人認証のセキュリティ向上

お客様による会員カードの偽造を防止するため、レジ担当者がお客様から会員カードをご提示いただいた後、レジにてカード認証を行うことが可能です。レジにて存在が確認された会員カードのみが通常通りご利用いただけます。

画像の説明を追加してください

この「会員カード クレジットカード認証」という設計思想がセッション認証の仕組みの本質です。

7. セッションの仕組み

画像の説明を追加してください

5.4 Expressでのセッション認証の使用

1. エクスプレスセッションミドルウェアをインストールする

Express プロジェクトでは、プロジェクトでセッション認証を使用するために Express-session ミドルウェアをインストールするだけで済みます。

npm install express-session
2. エクスプレスセッションミドルウェアの構成

Express-session ミドルウェアが正常にインストールされたら、app.use() を通じてセッション ミドルウェアを登録する必要があります。サンプル コードは次のとおりです。


3. セッションにデータを保存する

Express-session ミドルウェアが正常に構成されたら、 req.session を介してセッション オブジェクトにアクセスして使用し、ユーザーのキー情報を保存できます。


4. セッションからデータを取得する

req.sessionオブジェクトから以前に保存されたデータを直接取得できます。サンプルコードは次のとおりです。


5.セッションをクリアする

req.session.destroy()関数を呼び出して、サーバーによって保存されたセッション情報をクリアします。


5.5 JWT認証メカニズム

1. セッション認証の制限を理解する

セッション認証メカニズムは Cookie を使用して実装する必要があります。Cookie はデフォルトではクロスドメイン アクセスをサポートしていないため、バックエンド インターフェイスに対するフロントエンド クロスドメイン リクエストに関しては、クロスドメイン セッション認証を実現するために多くの追加構成が必要になります。

知らせ:

  • フロントエンドがバックエンド インターフェイスを要求し、クロスドメインの問題がない場合は、セッションID 認証メカニズムを使用することをお勧めします。
  • フロントエンドがドメインを越えてバックエンド インターフェイスを要求する必要がある場合、セッション認証メカニズムを使用することはお勧めできません。JWT 認証メカニズムを使用することをお勧めします。
2.JWTとは

JWT (英語の正式名: JSON Web Token) は、現在最も人気のあるクロスドメイン認証ソリューションです。

3. JWT の仕組み

画像の説明を追加してください

概要: ユーザー情報は、トークン文字列の形式でクライアント ブラウザに保存されます。サーバーはトークン文字列を復元することでユーザーの ID を認証します。

4. JWTのコンポーネント

JWT は通常、ヘッダー、ペイロード、署名の 3 つの部分で構成されます。

英語では 3 つは「.」で区切られており、形式は次のとおりです。

Header.Payload.Signature

以下は JWT 文字列の例です。


5. JWT の 3 つの部分は何を表しますか?

JWT の 3 つのコンポーネントは、前から後ろに、ヘッダー、ペイロード、署名です。

で:

  • ペイロード部分は実際のユーザー情報であり、ユーザー情報を暗号化して生成された文字列です。
  • ヘッダーと署名はセキュリティに関連する部分であり、トークンのセキュリティを確保するためのものです。

画像の説明を追加してください

6.JWTの使い方

クライアントは、サーバーから返された JWT を受信すると、通常、それを localStorage または sessionStorage に保存します。

その後、クライアントはサーバーと通信するたびに、ID 認証のためにこの JWT 文字列を取得する必要があります。推奨されるアプローチは、HTTPリクエスト ヘッダーのAuthorizationフィールドJWT を次の形式で配置することです。


5.6 Express での JWT の使用

1. JWT関連パッケージをインストールする

次のコマンドを実行して、次の 2 つの JWT 関連パッケージをインストールします。

npm install jsonwebtoken express-jwt

で:

  • jsonwebtoken はJWT文字列の生成 に使用されます
  • Express-jwt は、JWT文字列を解析して JSONオブジェクト復元するために使用されます。
2. JWT関連パッケージをインポートする

require()関数を使用して、2 つの JWT 関連パッケージをインポートします。


3. 秘密鍵を定義する

JWT 文字列のセキュリティを確保し、ネットワーク送信中に他の人によって JWT 文字列が解読されるのを防ぐために、暗号化復号化のための秘密キーを明確に定義する必要があります。

①JWT文字列を生成する際には、秘密鍵を使用してユーザー情報を暗号化し、最終的に暗号化されたJWT文字列を取得する必要があります。

②JWT文字列を解析してJSONオブジェクトに復元する際、復号化に秘密鍵を使用する必要がある

//3.secret 密钥的本质:就是一个字符串
const secretKey = '123445'
4. ログイン成功後に ** JWT 文字列を生成します

jsonwebtokenパッケージによって提供されるSign()メソッドを呼び出して、ユーザーの情報を JWT 文字列に暗号化し、クライアントに応答します。


5. JWT文字列をJSONオブジェクトに復元します

クライアントは、これらの承認されたインターフェイスにアクセスするたびに、リクエスト ヘッダーの Authorization フィールドを通じてID 認証のためにトークン文字列をサーバーにアクティブに送信する必要があります。

現時点では、サーバーは、**express-** jwtミドルウェアを通じて、クライアントから JSON オブジェクトに送信されたトークンを自動的に解析して復元できます。


6. req.user を使用してユーザー情報を取得します

Express-jwt ミドルウェアが正常に構成されたら、これらの承認されたインターフェイスでreq.userオブジェクトを使用して、JWT 文字列から解析されたユーザー情報にアクセスできます。サンプル コードは次のとおりです。


7. JWT の解析に失敗した後に生成されるキャプチャ エラー

Express-jwt を使用してトークン文字列を解析する場合、クライアントから送信されたトークン文字列が期限切れであるか不正な場合、解析失敗エラーが発生し、プロジェクトの通常の動作に影響します。このエラーをキャプチャし、Express のエラー ミドルウェアを通じて関連処理を実行できます。サンプル コードは次のとおりです。


見出し

ビッグ イベント バックエンド API プロジェクト。API インターフェイスのドキュメントについては、https://www.showdoc.cc/escook?page_id=3707158761215217 を参照してください。

1. 初期化

1.1 プロジェクトの作成

  1. api_serverプロジェクトのルート ディレクトリとして新しいフォルダーを作成し、プロジェクトのルート ディレクトリで次のコマンドを実行して、パッケージ管理構成ファイルを初期化します。
npm init -y
  1. 次のコマンドを実行して、特定のバージョンをインストールしますexpress
npm i [email protected]
  1. app.jsプロジェクトのルート ディレクトリにプロジェクト全体のエントリ ファイルとして新しいエントリ ファイルを作成し、次のコードを初期化します。
// 导入 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 cors クロスドメインの構成

  1. 次のコマンドを実行してcorsミドルウェアをインストールします。
npm i [email protected]
  1. ミドルウェアを次の場所にapp.jsインポートして構成します。cors
// 导入 cors 中间件
const cors = require('cors')
// 将 cors 注册为全局中间件
app.use(cors())

1.3 フォームデータを解析するためのミドルウェアを構成する

  1. 次のコードを使用して、次のapplication/x-www-form-urlencoded形式のフォーム データを解析するミドルウェアを構成します。
app.use(express.urlencoded({
    
     extended: false }))

1.4 ルーティング関連フォルダーの初期化

  1. プロジェクトのルート ディレクトリに、すべてのモジュールrouterを保存する新しいフォルダーを作成します。路由

    ルーティングモジュールには、クライアントのリクエストと処理機能の間のマッピング関係のみが保存されます。

  2. プロジェクトのルート ディレクトリに、router_handlerすべてを保存する新しいフォルダーを作成します。路由处理函数模块

    ルート処理機能モジュールは、具体的には各ルートに対応する処理機能を格納する役割を果たします。

1.5 ユーザールーティングモジュールの初期化

  1. routerフォルダー内に、user.jsユーザーのルーティング モジュールとして新しいファイルを作成します。初期化コードは次のとおりです。
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. app.js、インポートして使用します用户路由模块
// 导入并注册用户路由模块
const userRouter = require('./router/user')
app.use('/api', userRouter)

1.6 ユーザールーティングモジュールの処理機能の抽出

路由模块目的:の純度を確保するには、すべて路由处理函数を対応する抽出物路由处理函数模块に抽出する必要があります。

  1. では/router_handler/user.jsexportsオブジェクトを使用して次の 2 つを外部と共有します路由处理函数
/
 * 在这里定义和用户相关的路由处理函数,供 /router/user.js 模块进行调用
 */

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

// 登录的处理函数
exports.login = (req, res) => {
    
    
  res.send('login OK')
}
  1. /router/user.jsコードを次の構造に変更します。
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. ログインして登録する

2.1 新しい ev_users テーブルを作成する

  1. my_db_01データベースev_users次のように新しいテーブルを作成します:
    [外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (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%2 58B %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/ノード。 js%25E2%2580%2594%25E8 %25B5%2584%25E6%2596%2599/day8/ppt/images/1.jpg)]

2.2 mysql モジュールのインストールと構成

API インターフェイス プロジェクトでは、mysqlMySQL データベースに接続して操作するには、このサードパーティ モジュールをインストールして構成する必要があります。

  1. 次のコマンドを実行してmysqlモジュールをインストールします。
npm i [email protected]
  1. プロジェクトのルート ディレクトリに新しいファイルを作成し/db/index.js、このカスタム モジュールにデータベース接続オブジェクトを作成します。
// 导入 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 登録

2.3.0 実装手順

  1. フォームデータが合法かどうかを確認する
  2. ユーザー名が使用されているかどうかを確認する
  3. パスワードを暗号化する
  4. 新しいユーザーを挿入

2.3.1 フォームデータが正当かどうかを確認する

  1. ユーザー名とパスワードが空かどうかを確認する
// 接收表单数据
const userinfo = req.body
// 判断数据是否合法
if (!userinfo.username || !userinfo.password) {
    
    
  return res.send({
    
     status: 1, message: '用户名或密码不能为空!' })
}

2.3.2 ユーザー名が使用されているかどうかを検出する

  1. データベース操作モジュールをインポートします。
const db = require('../db/index')
  1. SQL ステートメントを定義します。
const sql = `select * from ev_users where username=?`
  1. SQL ステートメントを実行し、結果に基づいてユーザー名が占有されているかどうかを判断します。
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 パスワードの暗号化

パスワードのセキュリティを確保するために、明文ユーザーのパスワードを次の形式でデータベースに保存することはお勧めしません。加密存储


現在のプロジェクトでは、ユーザー パスワードを暗号化する方法を使用すると、bcryptjs次のような利点があります。

  • 暗号化されたパスワードを逆に解読することはできません
  • 同じ平文パスワードを複数回暗号化することで、得られる暗号化結果が異なるため、セキュリティが確保されます。

  1. 次のコマンドを実行して、指定したバージョンをインストールしますbcryptjs
npm i [email protected]
  1. /router_handler/user.js、インポートしますbcryptjs:
const bcrypt = require('bcryptjs')
  1. 登録ユーザーの処理関数では、ユーザー名が使用できることを確認した後、bcrypt.hashSync(明文密码, 随机盐的长度)ユーザーのパスワードを暗号化するメソッドを呼び出します。
// 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
userinfo.password = bcrypt.hashSync(userinfo.password, 10)

2.3.4 新しいユーザーの挿入

  1. ユーザーを挿入する SQL ステートメントを定義します。
const sql = 'insert into ev_users set ?'
  1. 呼び出してdb.query()SQL ステートメントを実行し、新しいユーザーを挿入します。
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 res.send() コードの最適化

処理関数では、res.send()クライアントに応答した处理失败結果を複数回呼び出す必要があるため、コードを簡素化するために、手動で res.cc() 関数をカプセル化できます。

  1. ではapp.js、すべてのルートの前に、グローバル ミドルウェアを宣言し、res.cc()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 フォームデータ検証の最適化

フォーム検証の原則: フロントエンド検証は補助的なものであり、バックエンド検証が主なものであり、バックエンドはフロントエンドによって送信されたものを決して信じてはなりません。

実際の開発では、フロントエンドとバックエンドの両方でフォームデータの正当性を検証する必要があり、また、バックエンドはデータの正当性検証の最後の関門として、不正データを遮断する重要な役割を果たします。

単にif...else...フォームを使用してデータの合法性を検証するだけでは非効率的で、エラー率が高く、保守性も悪くなります。したがって、エラー率を削減し、検証の効率と保守性を向上させ、バックエンド プログラマがコア ビジネス ロジックの処理により集中できるようにするために、サードパーティのデータ検証モジュールを使用することをお勧めします。

  1. パッケージをインストールし@hapi/joi、フォームに含まれる各データ項目の検証ルールを定義します。
npm install @hapi/[email protected]
  1. @escook/express-joiフォーム データの自動検証を実装するミドルウェアをインストールします。
npm i @escook/express-joi
  1. 新しいユーザー情報検証ルール モジュールを作成し/schema/user.js、次のようにコードを初期化します。
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. 変更された/router/user.jsコードは次のとおりです。
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. のグローバル エラー レベル ミドルウェアでapp.js、検証失敗のエラーをキャプチャし、検証失敗の結果をクライアントに応答します。
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 ログイン

2.6.0 実装手順

  1. フォームデータが合法かどうかを確認する
  2. ユーザー名に基づいてユーザーデータをクエリする
  3. ユーザーが入力したパスワードが正しいかどうかを確認する
  4. JWTトークン文字列を生成する

2.6.1 ログインフォームのデータが正当かどうかを確認する

  1. の宛先コードを次のように変更します/router/user.js登录
// 登录的路由
router.post('/login', expressJoi(reg_login_schema), userHandler.login)

2.6.2 ユーザー名に基づいてユーザー データをクエリする

  1. フォームデータを受信します。
const userinfo = req.body
  1. SQL ステートメントを定義します。
const sql = `select * from ev_users where username=?`
  1. SQL ステートメントを実行してユーザー データをクエリします。
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 ユーザーが入力したパスワードが正しいかどうかを確認する

主要な実装アイデア:bcrypt.compareSync(用户提交的密码, 数据库中的密码)パスワードが一貫しているかどうかを比較するメソッドを呼び出す

戻り値はブール値です (true は一貫性があり、false は一貫性がありません)。

具体的な実装コードは以下のとおりです。

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

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

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

2.6.4 JWT トークン文字列の生成

基本的な注意: トークン文字列を生成するときは、パスワードとアバターの値を必ず削除してください。

  1. ES6 の高度な構文を使用して、密码との値をすばやく削除します头像
// 剔除完毕之后,user 中只保留了用户的 id, username, nickname, email 这四个属性的值
const user = {
    
     ...results[0], password: '', user_pic: '' }
  1. 次のコマンドを実行して、トークン文字列を生成するパッケージをインストールします。
npm i [email protected]
  1. /router_handler/user.jsモジュールのヘッダー領域で、jsonwebtokenパッケージをインポートします。
// 用这个包来生成 Token 字符串
const jwt = require('jsonwebtoken')
  1. config.jsファイルを作成し、jwtSecretKey暗号化および復元トークンの文字列を外部に共有します。
module.exports = {
    
    
  jwtSecretKey: 'itheima No1. ^_^',
}
  1. ユーザー情報オブジェクトをトークン文字列に暗号化します。
// 导入配置文件
const config = require('../config')

// 生成 Token 字符串
const tokenStr = jwt.sign(user, config.jwtSecretKey, {
    
    
  expiresIn: '10h', // token 有效期为 10 个小时
})
  1. 生成されたトークン文字列をクライアントに応答します。
res.send({
    
    
  status: 0,
  message: '登录成功!',
  // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
  token: 'Bearer ' + tokenStr,
})

2.7 トークンを解析するためのミドルウェアの構成

  1. 次のコマンドを実行して、トークンを解析するためのミドルウェアをインストールします。
npm i express-jwt@5.3.3
  1. にルートを登録する前にapp.js、トークンを解析するミドルウェアを構成します。
// 导入配置文件
const config = require('./config')

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

// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
app.use(expressJWT({
    
     secret: config.jwtSecretKey }).unless({
    
     path: [/^\/api\//] }))
  1. では、トークン認証が失敗した後のエラーをキャプチャして処理しますapp.js错误级别中间件
// 错误中间件
app.use(function (err, req, res, next) {
    
    
  // 省略其它代码...

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

  // 未知错误...
})

3. パーソナルセンター

3.1 ユーザーの基本情報の取得

3.1.0 実装手順

  1. ルーティングモジュールの初期化
  2. ルート処理機能モジュールの初期化
  3. ユーザーの基本情報を取得する

3.1.1 ルーティングモジュールの初期化

  1. /router/userinfo.jsルーティング モジュールを作成し、次のコード構造を初期化します。
// 导入 express
const express = require('express')
// 创建路由对象
const router = express.Router()

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

// 向外共享路由对象
module.exports = router
  1. app.jsパーソナル センターのルーティング モジュールをインポートして使用します
// 导入并使用用户信息路由模块
const userinfoRouter = require('./router/userinfo')
// 注意:以 /my 开头的接口,都是有权限的接口,需要进行 Token 身份认证
app.use('/my', userinfoRouter)

3.1.2 ルーティング処理機能モジュールの初期化

  1. /router_handler/userinfo.jsルーティング処理汎用モジュールを作成し、次のコード構造を初期化します。
// 获取用户基本信息的处理函数
exports.getUserInfo = (req, res) => {
    
    
  res.send('ok')
}
  1. 変更された/router/userinfo.jsコードは次のとおりです。
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 ユーザーの基本情報の取得

  1. /router_handler/userinfo.jsデータベース操作モジュールをヘッドにインポートします。
// 导入数据库操作模块
const db = require('../db/index')
  1. SQL ステートメントを定義します。
// 根据用户的 id,查询用户的基本信息
// 注意:为了防止用户的密码泄露,需要排除 password 字段
const sql = `select id, username, nickname, email, user_pic from ev_users where id=?`
  1. db.query()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 ユーザーの基本情報を更新する

3.2.0 実装手順

  1. ルーティングおよび処理機能を定義する
  2. フォームデータを検証する
  3. ユーザー基本情報更新機能の実装

3.2.1 ルーティングおよび処理機能の定義

  1. /router/userinfo.jsモジュールで、更新用户基本信息新しいルートを追加します。
// 更新用户的基本信息
router.post('/userinfo', userinfo_handler.updateUserInfo)
  1. /router_handler/userinfo.jsモジュールで、更新用户基本信息ルート処理関数を外部に定義して共有します。
// 更新用户基本信息的处理函数
exports.updateUserInfo = (req, res) => {
    
    
  res.send('ok')
}

3.2.2 フォームデータの検証

  1. /schema/user.js検証ルール モジュールで、次のidように の検証ルールnicknameを定義しますemail
// 定义 id, nickname, emial 的验证规则
const id = joi.number().integer().min(1).required()
const nickname = joi.string().required()
const email = joi.string().email().required()
  1. そして、exports次のように外部共有するために使用します验证规则对象
// 验证规则对象 - 更新用户基本信息
exports.update_userinfo_schema = {
    
    
  body: {
    
    
    id,
    nickname,
    email,
  },
}
  1. モジュールで/router/userinfo.js、データの有効性を検証するミドルウェアをインポートします。
// 导入验证数据合法性的中间件
const expressJoi = require('@escook/express-joi')
  1. /router/userinfo.jsモジュールで、必要な検証ルール オブジェクトをインポートします。
// 导入需要的验证规则对象
const {
    
     update_userinfo_schema } = require('../schema/user')
  1. /router/userinfo.jsモジュールで、更新用户的基本信息ルーティングを次のように変更します。
// 更新用户的基本信息
router.post('/userinfo', expressJoi(update_userinfo_schema), userinfo_handler.updateUserInfo)

3.2.3 ユーザー基本情報更新機能の実装

  1. 実行する SQL ステートメントを定義します。
const sql = `update ev_users set ? where id=?`
  1. db.query()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('修改用户基本信息失败!')

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

3.3 パスワードのリセット

3.3.0 実装手順

  1. ルーティングおよび処理機能を定義する
  2. フォームデータを検証する
  3. パスワードリセット機能の実装

3.3.1 ルーティングおよび処理機能の定義

  1. /router/userinfo.jsモジュールで、重置密码新しいルートを追加します。
// 重置密码的路由
router.post('/updatepwd', userinfo_handler.updatePassword)
  1. /router_handler/userinfo.jsモジュールで、重置密码ルート処理関数を外部に定義して共有します。
// 重置密码的处理函数
exports.updatePassword = (req, res) => {
    
    
  res.send('ok')
}

3.3.2 フォームデータの検証

検証の中心的な考え方: 古いパスワードと新しいパスワードはパスワード検証ルールに準拠する必要があり、新しいパスワードは古いパスワードと一致することはできません。

  1. /schema/user.jsモジュールでは、exports次のように外部共有を使用します验证规则对象
// 验证规则对象 - 重置密码
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. /router/userinfo.jsモジュールで、必要な検証ルール オブジェクトをインポートします。
// 导入需要的验证规则对象
const {
    
     update_userinfo_schema, update_password_schema } = require('../schema/user')
  1. では重置密码的路由、ルールを使用してupdate_password_schemaフォームのデータを検証します。サンプル コードは次のとおりです。
router.post('/updatepwd', expressJoi(update_password_schema), userinfo_handler.updatePassword)

3.3.3 パスワードリセット機能の実装

  1. 次に従ってユーザーが存在するかどうかを確認します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. 送信された古いパスワードが正しいかどうかを確認します。
// 在头部区域导入 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. 新しいパスワードを暗号化した後bcrypt、それをデータベースに更新します。
// 定义更新用户密码的 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 ユーザーアバターの更新

3.4.0 実装手順

  1. ルーティングおよび処理機能を定義する
  2. フォームデータを検証する
  3. ユーザーアバター更新機能を実装

3.4.1 ルーティングおよび処理機能の定義

  1. /router/userinfo.jsモジュールで、更新用户头像新しいルートを追加します。
// 更新用户头像的路由
router.post('/update/avatar', userinfo_handler.updateAvatar)
  1. /router_handler/userinfo.jsモジュールで、更新用户头像ルート処理関数を外部に定義して共有します。
// 更新用户头像的处理函数
exports.updateAvatar = (req, res) => {
    
    
  res.send('ok')
}

3.4.2 フォームデータの検証

  1. /schema/user.js検証ルール モジュールでは、avatar定義された検証ルールは次のとおりです。
// dataUri() 指的是如下格式的字符串数据:
// data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=
const avatar = joi.string().dataUri().required()
  1. そして、exports次のように外部共有するために使用します验证规则对象
// 验证规则对象 - 更新头像
exports.update_avatar_schema = {
    
    
  body: {
    
    
    avatar,
  },
}
  1. /router/userinfo.jsモジュールで、必要な検証ルール オブジェクトをインポートします。
const {
    
     update_avatar_schema } = require('../schema/user')
  1. /router/userinfo.jsモジュールで、更新用户头像ルーティングを次のように変更します。
router.post('/update/avatar', expressJoi(update_avatar_schema), userinfo_handler.updateAvatar)

3.4.3 ユーザーアバター更新機能の実装

  1. ユーザーのアバターを更新する SQL ステートメントを定義します。
const sql = 'update ev_users set user_pic=? where id=?'
  1. を呼び出してdb.query()SQL ステートメントを実行し、対応するユーザーのアバターを更新します。
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. 品目分類管理

4.1 新しい ev_article_cate テーブルを作成する

4.1.1 テーブル構造の作成

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが備わっている可能性があります。画像を保存して直接アップロードすることをお勧めします (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%25 91 %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%2594%25E8% 25B5%2584%25E6%2596 %2599/day8/ppt/images/2.jpg)]

4.1.2 2 つの新しい初期データを追加する

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが備わっている可能性があります。画像を保存して直接アップロードすることをお勧めします (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%25 91 %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%2594%25E8% 25B5%2584%25E6%2596 %2599/day8/ppt/images/3.jpg)]

4.2 記事分類リストの取得

4.2.0 実装手順

  1. ルーティングモジュールの初期化
  2. ルート処理機能モジュールの初期化
  3. 記事分類リストデータの取得

4.2.1 ルーティングモジュールの初期化

  1. /router/artcate.jsルーティング モジュールを作成し、次のコード構造を初期化します。
// 导入 express
const express = require('express')
// 创建路由对象
const router = express.Router()

// 获取文章分类的列表数据
router.get('/cates', (req, res) => {
    
    
  res.send('ok')
})

// 向外共享路由对象
module.exports = router
  1. app.js記事分類のルーティング モジュールをインポートして使用します
// 导入并使用文章分类路由模块
const artCateRouter = require('./router/artcate')
// 为文章分类的路由挂载统一的访问前缀 /my/article
app.use('/my/article', artCateRouter)

4.2.2 ルート処理機能モジュールの初期化

  1. /router_handler/artcate.jsルーティング処理汎用モジュールを作成し、次のコード構造を初期化します。
// 获取文章分类列表数据的处理函数
exports.getArticleCates = (req, res) => {
    
    
  res.send('ok')
}
  1. 変更された/router/artcate.jsコードは次のとおりです。
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 物品分類リストデータの取得

  1. /router_handler/artcate.jsデータベース操作モジュールをヘッドにインポートします。
// 导入数据库操作模块
const db = require('../db/index')
  1. SQL ステートメントを定義します。
// 根据分类的状态,获取所有未被删除的分类列表数据
// is_delete 为 0 表示没有被 标记为删除 的数据
const sql = 'select * from ev_article_cate where is_delete=0 order by id asc'
  1. db.query()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 新しい記事カテゴリを追加する

4.3.0 実装手順

  1. ルーティングおよび処理機能を定義する
  2. フォームデータを検証する
  3. 分类名称と が分类别名占有されているかどうかを問い合わせます
  4. 新規記事カテゴリ追加機能を実装

4.3.1 ルーティングおよび処理機能の定義

  1. /router/artcate.jsモジュールに、新增文章分类次のルートを追加します。
// 新增文章分类的路由
router.post('/addcates', artcate_handler.addArticleCates)
  1. /router_handler/artcate.jsモジュールで、新增文章分类ルート処理関数を外部に定義して共有します。
// 新增文章分类的处理函数
exports.addArticleCates = (req, res) => {
    
    
  res.send('ok')
}

4.3.2 フォームデータの検証

  1. /schema/artcate.js記事分類データ検証モジュールを作成し、次の検証ルールを定義します。
// 导入定义验证规则的模块
const joi = require('@hapi/joi')

// 定义 分类名称 和 分类别名 的校验规则
const name = joi.string().required()
const alias = joi.string().alphanum().required()

// 校验规则对象 - 添加分类
exports.add_cate_schema = {
    
    
  body: {
    
    
    name,
    alias,
  },
}
  1. /router/artcate.jsモジュールで、add_cate_schema以下を使用してデータを検証します。
// 导入验证数据的中间件
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 カテゴリ名とエイリアスが占有されているかどうかを問い合わせる

  1. 重複チェック用の SQL ステートメントを定義します。
// 定义查询 分类名称 与 分类别名 是否被占用的 SQL 语句
const sql = `select * from ev_article_cate where name=? or alias=?`
  1. db.query()重複チェック操作を実行するために呼び出します。
// 执行查重操作
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 新規記事カテゴリ追加機能の実装

  1. 新しい記事カテゴリを定義する SQL ステートメント:
const sql = `insert into ev_article_cate set ?`
  1. db.query()新しい記事カテゴリを追加するための SQL ステートメントを実行するために呼び出します。
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 IDに基づいて記事カテゴリを削除する

4.4.0 実装手順

  1. ルーティングおよび処理機能を定義する
  2. フォームデータを検証する
  3. 記事カテゴリ削除機能を実装

4.4.1 ルーティングおよび処理機能の定義

  1. /router/artcate.jsモジュールに、删除文章分类次のルートを追加します。
// 删除文章分类的路由
router.get('/deletecate/:id', artcate_handler.deleteCateById)
  1. /router_handler/artcate.jsモジュールで、删除文章分类ルート処理関数を外部に定義して共有します。
// 删除文章分类的处理函数
exports.deleteCateById = (req, res) => {
    
    
  res.send('ok')
}

4.4.2 フォームデータの検証

  1. 検証ルール モジュールで/schema/artcate.js、次のように ID の検証ルールを定義します。
// 定义 分类Id 的校验规则
const id = joi.number().integer().min(1).required()
  1. そして、exports次のように外部共有するために使用します验证规则对象
// 校验规则对象 - 删除分类
exports.delete_cate_schema = {
    
    
  params: {
    
    
    id,
  },
}
  1. /router/artcate.jsモジュールで、必要な検証ルール オブジェクトをインポートし、ルーティングで使用します。
// 导入删除分类的验证规则对象
const {
    
     delete_cate_schema } = require('../schema/artcate')

// 删除文章分类的路由
router.get('/deletecate/:id', expressJoi(delete_cate_schema), artcate_handler.deleteCateById)

4.4.3 記事カテゴリ削除機能の実装

  1. 記事カテゴリを削除する SQL ステートメントを定義します。
const sql = `update ev_article_cate set is_delete=1 where id=?`
  1. db.query()記事分類を削除する SQL ステートメントを実行する呼び出し:
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 IDに基づく記事分類データの取得

4.5.0 実装手順

  1. ルーティングおよび処理機能を定義する
  2. フォームデータを検証する
  3. 記事分類取得機能の実装

4.5.1 ルーティングおよび処理機能の定義

  1. /router/artcate.jsモジュールに、根据 Id 获取文章分类次のルートを追加します。
router.get('/cates/:id', artcate_handler.getArticleById)
  1. /router_handler/artcate.jsモジュールで、根据 Id 获取文章分类ルート処理関数を外部に定義して共有します。
// 根据 Id 获取文章分类的处理函数
exports.getArticleById = (req, res) => {
    
    
  res.send('ok')
}

4.5.2 フォームデータの検証

  1. /schema/artcate.js検証ルール モジュールでは、exports次のように外部共有を使用します验证规则对象
// 校验规则对象 - 根据 Id 获取分类
exports.get_cate_schema = {
    
    
  params: {
    
    
    id,
  },
}
  1. /router/artcate.jsモジュールで、必要な検証ルール オブジェクトをインポートし、ルーティングで使用します。
// 导入根据 Id 获取分类的验证规则对象
const {
    
     get_cate_schema } = require('../schema/artcate')

// 根据 Id 获取文章分类的路由
router.get('/cates/:id', expressJoi(get_cate_schema), artcate_handler.getArticleById)

4.5.3 記事分類取得機能の実装

  1. ID に基づいて記事の分類を取得する SQL ステートメントを定義します。
const sql = `select * from ev_article_cate where id=?`
  1. db.query()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 IDに基づいて記事分類データを更新する

4.6.0 実装手順

  1. ルーティングおよび処理機能を定義する
  2. フォームデータを検証する
  3. 分类名称と が分类别名占有されているかどうかを問い合わせます
  4. 記事分類更新機能を実装

4.6.1 ルーティングおよび処理機能の定義

  1. /router/artcate.jsモジュールに、更新文章分类次のルートを追加します。
// 更新文章分类的路由
router.post('/updatecate', artcate_handler.updateCateById)
  1. /router_handler/artcate.jsモジュールで、更新文章分类ルート処理関数を外部に定義して共有します。
// 更新文章分类的处理函数
exports.updateCateById = (req, res) => {
    
    
  res.send('ok')
}

4.6.2 フォームデータの検証

  1. /schema/artcate.js検証ルール モジュールでは、exports次のように外部共有を使用します验证规则对象
// 校验规则对象 - 更新分类
exports.update_cate_schema = {
    
    
  body: {
    
    
    Id: id,
    name,
    alias,
  },
}
  1. /router/artcate.jsモジュールで、必要な検証ルール オブジェクトをインポートし、ルーティングで使用します。
// 导入更新文章分类的验证规则对象
const {
    
     update_cate_schema } = require('../schema/artcate')

// 更新文章分类的路由
router.post('/updatecate', expressJoi(update_cate_schema), artcate_handler.updateCateById)

4.5.4 カテゴリ名とエイリアスが占有されているかどうかを問い合わせる

  1. 重複チェック用の SQL ステートメントを定義します。
// 定义查询 分类名称 与 分类别名 是否被占用的 SQL 语句
const sql = `select * from ev_article_cate where Id<>? and (name=? or alias=?)`
  1. db.query()重複チェック操作を実行するために呼び出します。
// 执行查重操作
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 記事分類更新機能の実装

  1. 記事の分類を更新する SQL ステートメントを定義します。
const sql = `update ev_article_cate set ? where Id=?`
  1. db.query()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. 記事管理

5.1 新しい ev_articles テーブルを作成する

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが備わっている可能性があります。画像を保存して直接アップロードすることをお勧めします (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%25 91 %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%2594%25E8% 25B5%2584%25E6%2596 %2599/day8/ppt/images/4.jpg)]

5.2 新しい記事の公開

5.2.0 実装手順

  1. ルーティングモジュールの初期化
  2. ルート処理機能モジュールの初期化
  3. multerを使用してフォームデータを解析する
  4. フォームデータを検証する
  5. 記事公開機能の実装

5.2.1 ルーティングモジュールの初期化

  1. /router/article.jsルーティング モジュールを作成し、次のコード構造を初期化します。
// 导入 express
const express = require('express')
// 创建路由对象
const router = express.Router()

// 发布新文章
router.post('/add', (req, res) => {
    
    
  res.send('ok')
})

// 向外共享路由对象
module.exports = router
  1. app.js記事のルーティング モジュールをインポートして使用します
// 导入并使用文章路由模块
const articleRouter = require('./router/article')
// 为文章的路由挂载统一的访问前缀 /my/article
app.use('/my/article', articleRouter)

5.2.2 ルート処理機能モジュールの初期化

  1. /router_handler/article.jsルーティング処理汎用モジュールを作成し、次のコード構造を初期化します。
// 发布新文章的处理函数
exports.addArticle = (req, res) => {
    
    
  res.send('ok')
}
  1. 変更された/router/article.jsコードは次のとおりです。
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 multer を使用してフォームデータを解析する

注:形式のリクエスト本文データは、express.urlencoded()ミドルウェアを使用して解析できません。multipart/form-data

multipart/form-data現在のプロジェクトでは、multer を使用してフォーム データを解析することをお勧めします。https://www.npmjs.com/package/multer

  1. 次のターミナル コマンドを実行して、プロジェクトにインストールしますmulter
npm i [email protected]
  1. module/router_handler/article.jsでインポートして構成しますmulter
// 导入解析 formdata 格式表单数据的包
const multer = require('multer')
// 导入处理路径的核心模块
const path = require('path')

// 创建 multer 的实例对象,通过 dest 属性指定文件的存放路径
const upload = multer({
    
     dest: path.join(__dirname, '../uploads') })
  1. 変更後の发布新文章ルートは以下の通りです。
// 发布新文章的路由
// upload.single() 是一个局部生效的中间件,用来解析 FormData 格式的表单数据
// 将文件类型的数据,解析并挂载到 req.file 属性中
// 将文本类型的数据,解析并挂载到 req.body 属性中
router.post('/add', upload.single('cover_img'), article_handler.addArticle)
  1. /router_handler/article.jsmodule の処理関数addArticlemulter解析されたデータを出力します。
// 发布新文章的处理函数
exports.addArticle = (req, res) => {
    
    
  console.log(req.body) // 文本类型的数据
  console.log('--------分割线----------')
  console.log(req.file) // 文件类型的数据

  res.send('ok')
})

5.2.4 フォームデータの検証

実装案:req.body内のテキストデータはexpress-joiで自動検証、req.file内のファイルデータはif判定により手動検証。

  1. /schema/article.js検証ルールモジュールを作成し、次のコード構造を初期化します。
// 导入定义验证规则的模块
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. /router/article.jsモジュールで、必要な検証ルール オブジェクトをインポートし、ルーティングで使用します。
// 导入验证数据的中间件
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. /router_handler/article.jsモジュールの処理関数addArticleifクライアントが送信したかどうかを判断します封面图片
// 发布新文章的处理函数
exports.addArticle = (req, res) => {
    
    
    // 手动判断是否上传了文章封面
  if (!req.file || req.file.fieldname !== 'cover_img') return res.cc('文章封面是必选参数!')

  // TODO:表单数据合法,继续后面的处理流程...
})

5.2.5 記事公開機能の実装

  1. データベースに挿入する記事情報オブジェクトを整理します。
// 导入处理路径的 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. 記事を公開するための SQL ステートメントを定義します。
const sql = `insert into ev_articles set ?`
  1. db.query()記事を公開するための SQL ステートメントを実行するために呼び出します。
// 导入数据库操作模块
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. ではapp.jsexpress.static()ミドルウェアを使用して、uploadsディレクトリ内のイメージを静的リソースとしてホストします。
// 托管静态资源文件
app.use('/uploads', express.static('./uploads'))

画像の説明を追加してください
画像の説明を追加してください

おすすめ

転載: blog.csdn.net/qq_66970557/article/details/128841735