【学習ノート】Node - 基礎0から実戦まで エンタープライズ公式サイト

前書き:この記事は、Node 中間層の学習の実践に関連しています。元の記事Node-From 0 Basics to the Actual Enterprise Official Website
    by jsliangを読むことをお勧めしますこの記事を始める前に、まずノードの基本的な知識を理解しておくと、この記事の内容を理解するのに役立ちます。もちろん、この記事に従って、読みながら学習することもできます。(追記:借金返済を続けるノードシャオバイ╮(╯▽╰)╭)

この記事のハイライト:

1.基礎学習

1.1 HTTP – ノードの開始

http.js の関連コード:

// 1. 引入 http 模块
var http = require("http");

// 2. 用 http 模块创建服务
/**
 * req 获取 url 信息 (request)
 * res 浏览器返回响应信息 (response)
 */
http.createServer(function (req, res) {
    
    
  // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
  res.writeHead(200, {
    
    
    "Content-Type": "text/html;charset=UTF-8"
  });

  // 往页面打印值
  res.write('<h1 style="text-align:center">Hello NodeJS</h1>');

  // 结束响应
  res.end();

}).listen(3000); // 监听的端口

では、上記のコードをどのように使用するのでしょうか?

  • まず、上記のコードをコピーして http.js に貼り付けます。
  • 次に、VS Code ターミナルを起動します: Ctrl + ~ ;
  • 次に、ノード http.js と入力して Enter キーを押します。
  • 最後に、localhost:3000を開きます

ここに画像の説明を挿入
さて、それでは、上記のコードを説明しましょう。
まず、HTTP モードを有効にする必要があります。一般に、PHP のような昔ながらのバックエンド言語では、HTTP サービスを有効にするために Apache または Nginx が必要です。ただし、ノードでは次のことを行う必要はありません。

var http = require("http");

次に、HTTP サービスを開始し、開いているポートを設定します。

/**
 * req 获取 url 信息 (request)
 * res 浏览器返回响应信息 (response)
 */
http.createServer(function (req, res) {
    
    
  // ... 步骤 3 代码
}).listen(3000); // 监听的端口

次に、HTTP ヘッダーを設定し、値をページに出力し、最後に応答を終了します。

// 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
res.writeHead(200, {
    
    
  "Content-Type": "text/html;charset=UTF-8"
});

// 往页面打印值
res.write('<h1 style="text-align:center">Hello NodeJS</h1>');

// 结束响应 
res.end();

最後に、ブラウザに入力すると、http://localhost:3000/開いた Node サービスにアクセスして、ページをレンダリングします。
ここまでで、ノードへの取り組みを開始しました。

1.2 URLモジュール

URLモジュールとは何ですか? コンソール (ターミナル)でノード モードを開き
、それを印刷urlして確認ますすると
ここに画像の説明を挿入
非常に多くのモジュールがあることがわかりました。では、これらのモジュールは何のためにあるのでしょうか? まずコードを見てみましょう: url.jsUrlparseresolveresolveObjectformatURLURLSearchParamsdomainToASCIIdomainToUnicode


// 1. 引入 url 模块
var url = require("url");

// 2. 引入 http 模块
var http = require("http");

// 3. 用 http 模块创建服务
/**
 * req 获取 url 信息 (request)
 * res 浏览器返回响应信息 (response)
 */
http.createServer(function (req, res) {
    
    

  // 4. 获取服务器请求
  /**
   * 访问地址是:http://localhost:3000/?userName=jsliang&userAge=23
   * 如果你执行 console.log(req.url),它将执行两次,分别返回下面的信息:
   * /  ?userName=jsliang&userAge=23
   * /  /favicon.ico
   * 这里为了防止重复执行,所以排除 req.url == /favicon.ico 的情况
   */
  if(req.url != "/favicon.ico") {
    
    
    
    // 5. 使用 url 的 parse 方法
    /**
     * parse 方法需要两个参数:
     * 第一个参数是地址
     * 第二个参数是 true 的话表示把 get 传值转换成对象
     */ 
    var result = url.parse(req.url, true);
    console.log(result);
    /**
     * Url {
     *   protocol: null,
     *   slashes: null,
     *   auth: null,
     *   host: null,
     *   port: null,
     *   hostname: null,
     *   hash: null,
     *   search: '?userName=jsliang&userAge=23',
     *   query: { userName: 'jsliang', userAge: '23' },
     *   pathname: '/',
     *   path: '/?userName=jsliang&userAge=23',
     *   href: '/?userName=jsliang&userAge=23' }
     */

    console.log(result.query.userName); // jsliang

    console.log(result.query.userAge); // 23
  }

  // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
  res.writeHead(200, {
    
    
    "Content-Type": "text/html;charset=UTF-8"
  });

  // 往页面打印值
  res.write('<h1 style="text-align:center">Hello NodeJS</h1>');

  // 结束响应
  res.end();

}).listen(3000);

上記のコードでは、
まずurl、この章の主人公モジュールを導入します。

// 1.引入url模块
var url = require("url");

次に、http モジュールをインポートします。

// 2.引入http模块
var http = require("http");

次に監視にはモジュールを開く必要があるhttpため、モジュールを作成します。urlhttp

// 3.用http模块创建服务
/**
* req获取url信息 (request)
* res 游览器返回响应信息 (response)
*/
http.createServer(function (req, res) {
    
    
 // ...第4步、第5步代码
 // 设置HTTP头部,状态码是200,文件类型是html,字符集是utf8
 res.writeHead(200, {
    
    
	"Content-Type": "text/html;charset=UTF-8"	
 });
 //往页面打印值
 res.write('<h1 style="text-align:center">Hello World</h1>');
 //结束响应
 res.end();
}).listen(3000);

最後に、指定されたアドレスにアクセスしhttp://localhost:3000/?userName=jsliang&userAge=23 、それを使用してモジュールがurlどのように使用され、出力が何であるかを確認します。parse

// 4.获取服务器请求
/**
*访问地址是:http://localhost:3000/?userName=jsliang&userAge=23
*如果执行console.log(req.url),它将执行两次,分别返回下面的信息:
*/ ?userName=jsliang&userAge=23
*/ /favicon.ico
*这里为了防止重复执行,所以排除req.url == /favicon.ico的情况
*/
if(req.url != "/favicon.ico") {
    
    
	//5. 使用url的parse方法
	/**
	*parse方法需要两个参数:
	*第一个参数是地址
	*第二个参数是true的话表示把get传值转换给对象
	*/
	var result = url.parse(req.url, true);
	console.log(result);
	/**
	*Url {
	* protocol: null,
	* slashes: null,
	* auth: null,
	* host: null,
	* port: null,
	* hostname: null,
	* hash: null,
	* search: '?userName=jsliang&userAge=23',
	* query: { userName: 'jsliang',userAge: '23'},
	* pathname: '/',
	* path: '/?userName=jsliang&userAge=23',
	* href: '/?userName=jsliang&userAge=23'}
	* /
	console.log(result.query.userName); //jsliang
	console.log(result.query.userAge); // 23
}

queryそこから、必要なパス フィールドが を通じて取得できることがわかります。
もちろん、上記はparse使い方を説明しただけなので、上記のコード内の if ステートメント内のコードをすべてクリアすることもできます。次に、次の内容を入力してurlモジュールの詳細を確認します。

  • コンテンツ 1: URL モジュールのすべてのコンテンツ
console.log(url);

/**
 * Console:
 { 
   Url: [Function: Url],
    parse: [Function: urlParse], // 获取地址信息
    resolve: [Function: urlResolve], // 追加或者替换地址
    resolveObject: [Function: urlResolveObject],
    format: [Function: urlFormat], // 逆向 parse,根据地址信息获取原 url 信息
    URL: [Function: URL],
    URLSearchParams: [Function: URLSearchParams],
    domainToASCII: [Function: domainToASCII],
    domainToUnicode: [Function: domainToUnicode] 
  }
 */
  • 内容2:parseの使い方
console.log(url.parse("http://www.baidu.com"));
/**
 * Console:
  Url {
    protocol: 'http:',
    slashes: true,
    auth: null,
    host: 'www.baidu.com',
    port: null,
    hostname: 'www.baidu.com',
    hash: null,
    search: null,
    query: null,
    pathname: '/',
    path: '/',
    href: 'http://www.baidu.com/' 
  }
 */
  • 内容 3: パラメーターを使用して解析する
console.log(url.parse("http://www.baidu.com/new?name=zhangsan"));

/**
 * Console:
  Url {
    protocol: 'http:',
    slashes: true,
    auth: null,
    host: 'www.baidu.com',
    port: null,
    hostname: 'www.baidu.com',
    hash: null,
    search: '?name=zhangsan',
    query: 'name=zhangsan',
    pathname: '/new',
    path: '/new?name=zhangsan',
    href: 'http://www.baidu.com/new?name=zhangsan' 
  }
 */
  • コンテンツ 4:formatの使用
console.log(url.format({
    
    
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.baidu.com',
  port: null,
  hostname: 'www.baidu.com',
  hash: null,
  search: '?name=zhangsan',
  query: 'name=zhangsan',
  pathname: '/new',
  path: '/new?name=zhangsan',
  href: 'http://www.baidu.com/new?name=zhangsan' 
}))

// Console:
// http://www.baidu.com/new?name=zhangsan
  • 内容5:決意の使い方
console.log(url.resolve("http://www.baidu.com/jsliang", "梁峻荣"));

// Console:
// http://www.baidu.com/梁峻荣

URL設定の詳細については、公式Webサイトを確認してください。

1.3 共通JS

  • CommonJS とは
    CommonJS は、JS のパフォーマンスに関する仕様を策定することです。JS にはモジュール システムがなく、標準ライブラリが少なく、パッケージ管理ツールが不足しているため、CommonJS が登場しました。JS が場所だけでなくどこでも実行できることを期待しています。サーバーでは、Java、C#、PHP などのバックエンド言語が大規模なアプリケーションを開発する機能を備えています。

  • CommonJSの応用?
    1. サーバーサイド JavaScript アプリケーション、(Node.js)
    2. コマンド ライン ツール、
    3. デスクトップ GUI アプリケーション。

  • CommonJS と Node.js の関係は?
    CommonJS はモジュール型の標準であり、Node.js は CommonJS (モジュール型) の実装です。

  • Node.jsのモジュール性?
    1. Node では、モジュールは 2 つのカテゴリに分類されます: 1 つは Node によって提供されるモジュール (コア モジュールと呼ばれます)、もう 1 つはユーザーが作成するモジュール (ファイル モジュールと呼ばれます) です。Node ソース コードのコンパイル プロセス中に、コア モジュールはバイナリ実行ファイルをコンパイルするため、HTTP モジュール、URL モジュール、FS モジュールなどのロード速度が最速になります。ファイル モジュールは実行時に動的にロードされ、完全なパス、ファイルの場所、コンパイルと実行プロセスなどが分析されるため、その速度はコア モジュールよりも遅くなります。
    2. パブリック関数を保存用に別の JS ファイルに抽出し、必要に応じて、export または module.exports を通じてモジュールをエクスポートし、require を通じてこれらのモジュールをインポートできます。
    では、Nodeにおけるモジュール化とexport/requireの使い方を3つの利用方法を通して解説していきます。
    まずディレクトリをチェックアウトします。
    ここに画像の説明を挿入

  • 方法 1:
    まず、03_CommonJS.js03_tool-add.jsnode_modules/03_tool-multiply.jsnode_modules/jsliang-module/tools.jsの 4 つのファイル/フォルダーを作成します。
    このうちpackage.jsonはとりあえず無視し、どのように自動生成されるかは後ほど説明します。
    03_tool-add.js:
    03_tool-add.js

// 1. 假设我们文件其中有个工具模块
var tools = {
    
    
  add: (...numbers) => {
    
    
    let sum = 0;
    for (let number in numbers) {
    
    
      sum += numbers[number];
    }
    return sum;
  }
}

/**
 * 2. 暴露模块
 * exports.str = str;
 * module.exports = str;
 * 区别:
 * module.exports 是真正的接口
 * exports 是一个辅助工具
 * 如果 module.exports 为空,那么所有的 exports 收集到的属性和方法,都赋值给了 module.exports
 * 如果 module.exports 具有任何属性和方法,则 exports 会被忽略
 */

// exports 使用方法
// var str = "jsliang is very good!";
// exports.str = str; // { str: 'jsliang is very good!' }

// module.exports 使用方法
module.exports = tools;

では、上記のコードの定義は何でしょうか?
最初のステップでは、ツール ライブラリが定義されますtools。2
番目のステップでは、ツール ライブラリがを通じてエクスポートされmodules.exportsますtools
したがって、次の場所でインポートして使用03_CommonJS.jsできます。require

var http = require("http");

var tools1 = require('./03_tool-add');

http.createServer(function (req, res) {
    
    

  res.writeHead(200, {
    
    
    "Content-Type": "text/html;charset=UTF-8"
  });

  res.write('<h1 style="text-align:center">Hello NodeJS</h1>');
  
  console.log(tools1.add(1, 2, 3));
  /**
   * Console:
   * 6
   * 6
   * 这里要记得 Node 运行过程中,它请求了两次,
   * http://localhost:3000/ 为一次,
   * http://localhost:3000/favicon.ico 为第二次
   */
  
  res.end();

}).listen(3000);

exports以上で、との初期利用が完了しますrequire

  • 方法 2:モジュール ファイルが多すぎる場合、これらのモジュールを格納するディレクトリを用意する必要があります。Node は非常に信頼性が高く、これらのファイルをハウス ディレクトリに
    格納できるように規定されています。したがって、次の内容の新しいファイルを に作成します: 03_tool-multiply.jsnode_modules
    node_modules03_tool-multiply.js
var tools = {
    
    
	multiply: (...numbers) => {
    
    
		let sum = numbers[0];
		for (let number in numbers) {
    
    
			sum = sunm * numbers[numbers];
		}
		return sum;
	}
}
module.exports = tools;

参照に関しては、次のように渡すだけです。

// 如果Node在当前目录没找到too.js 文件,则会去node_modules 里面去查找
var tools2 = require('03_tool-multiply');

console.log(tools2.multiply(1,2,3,4));

このようにして、ファイルは正常にインポートされます03_tool-multiply.js

  • 方法 3:
    すべての単一ファイルが にスローされるとnode_modules、整理されていないように見えるため、独自のモジュールを定義し、次のディレクトリに保存する必要があります: jsliang-modulejsliang-module / tool.jstools.js
var tools = {
    
    
  add: (...numbers) => {
    
    
    let sum = 0;
    for (let number in numbers) {
    
    
      sum += numbers[number];
    }
    return sum;
  },
  multiply: (...numbers) => {
    
    
    let sum = numbers[0];
    for (let number in numbers) {
    
    
      sum = sum * numbers[number];
    }
    return sum;
  }
}

module.exports = tools;

このようにして、独自のツール ライブラリを定義しました。
ただし、var tools3 = require('jsliang-module'); を使用してインポートすると、エラーが報告されることがわかるため、次のコマンド ラインを使用して jsliang-module ディレクトリに package.json を生成する必要があります。

PS E:\MyWeb\node_modules\jsliang-nodule>npm init --yes

このように、jsliang-module には package.json があり、
それを 03_CommonJS.js にインポートできます。

03_CommonJS.js

var http = require("http");

var tools1 = require('./03_tool-add');

// 如果 Node 在当前目录没找到 tool.js 文件,则会去 node_modules 里面去查找
var tools2 = require('03_tool-multiply');

/**
 * 通过 package.json 来引用文件
 * 1. 通过在 jsliang-module 中 npm init --yes 来生成 package.json 文件
 * 2. package.json 文件中告诉了程序入口文件为 :"main": "tools.js",
 * 3. Node 通过 require 查找 jsliang-module,发现它有个 package.json
 * 4. Node 执行 tools.js 文件
 */
var tools3 = require('jsliang-module');

http.createServer(function (req, res) {
    
    

  res.writeHead(200, {
    
    
    "Content-Type": "text/html;charset=UTF-8"
  });

  res.write('<h1 style="text-align:center">Hello NodeJS</h1>');
  
  console.log(tools1.add(1, 2, 3));
  console.log(tools2.multiply(1, 2, 3, 4));
  console.log(tools3.add(4, 5, 6));
  /**
   * Console:
   * 6
   * 24
   * 15
   * 6
   * 24
   * 15
   * 这里要记得 Node 运行过程中,它请求了两次,
   * http://localhost:3000/ 为一次,
   * http://localhost:3000/favicon.ico 为第二次
   */
  
  res.end();

}).listen(3000);

これまで、 3 つの方法を通じてさまざまexports姿勢と Node モジュール化の概念について学習してきました。require

1.4 fs ファイル管理

次に、fs ファイル管理について説明します。

次のいずれかをすばやく見つけるには、Ctrl + F を使用します。

  1. fs.statファイルかディレクトリかを検出します。
  2. fs.mkdirディレクトリを作成します。
  3. fs.writeFile書き込みファイルを作成します。
  4. fs.appendFileファイルを追加する
  5. fs.readFileファイルを読み取ります。
  6. fs.readdirディレクトリを読み取ります。
  7. fs.rename 重命名 ;
  8. fs.rmdirディレクトリを削除します。
  9. fs.unlinkファイルを削除します。

この章のファイル ディレクトリ:
ここに画像の説明を挿入
まず、ファイルまたはディレクトリが fs.stat によって読み取られるかどうかを確認します。

05_fs.js

// 2. fs.mkdir
let fs = require('fs');

/**
* 接收参数
 * path - 将创建的目录路径
 * mode - 目录权限(读写权限),默认 0777
 * callback - 回调,传递异常参数 err
 */
 fs.mkdir('css', (err) => {
    
    
	if(err) {
    
    
		console.log(err);
		return false;
	} else {
    
    
	    console.log("创建目录成功");
	    // Console: 创建目录成功!
	}
 })

合格するnode 05_fs.jsと、ディレクトリ内にもう 1 つのcssフォルダー。
作成したら削除することになるのですが、作成したディレクトリを削除するにはどうすればよいでしょうか?説明は次のとおりですfs.rmdir:
05_fs.js

// 8. fs.rmdir
let fs = require('fs');

/**
 * 接收参数
 * path - 将创建的目录路径
 * mode - 目录权限(读写权限),默认 0777
 * callback - 回调,传递异常参数 err
 */
 fs.rmdir('css',(err) => {
    
    
	if(err) {
    
    
		console.log(err);
		return false;
	} else {
    
    
		console.log("创建目录成功");
		// Console: 创建目录成功!
	}
 })

を確認したところnode 05_fs.js、ディレクトリ内のcssフォルダーが。
次に、 05_fs.jsfs.writeFile書き込みファイルを作成します。

// 3. fs.writeFile
let fs = require('fs');

/**
 * filename (String) 文件名称
 * data (String | Buffer) 将要写入的内容,可以是字符串或者 buffer 数据。
 * · encoding (String) 可选。默认 'utf-8',当 data 是 buffer 时,该值应该为 ignored。
 * · mode (Number) 文件读写权限,默认 438。
 * · flag (String) 默认值 'w'。
 * callback { Function } 回调,传递一个异常参数 err。
 */

fs.writeFile('index.js','Hello jsliang', (err) => {
    
    
	if(err) {
    
    
		console.log(err);
		return false;
	} else {
    
    
		console.log('写入成功');
	}
})

Hello jsliangこの種の書き込みでは、元のファイルのデータをすべてクリアしてから、この文  を追加することに注意してください。つまり、存在する場合は上書きされ、存在しない場合は作成されます。

  作成があれば削除があるので、興味があれば を使ってファイルを削除するfs.unlinkこと、これもあまり説明しません。
  上記はオーバーレイファイルなので追加ファイルはあるのでしょうか?はい、使ってfs.appendFileください:
05_fs.js

// 4. fs.appendFile
let fs = require('fs');

fs.appendFile('index.js','这段文本是要追加的内容',(err) => {
    
    
	if(err) {
    
    
		console.log(err);
		return false;
	} else {
    
    
		console.log("追加成功");
	}
})

このようにして、段落が正常に追加されるためindex.js
次のようになります。

こんにちは、jsliang このテキストは追加される内容です

上記では、追加、変更、削除の操作を実行しました。したがって、友人たちは次に何をすべきかを熟知している必要があります。

  • fs.readFileファイルを読み取ります。
  • fs.readdirディレクトリの読み取り
let fs = require('fs');

// 5. fs.readFile
fs.readFile('index.js', (err, data) => {
    
    
  if(err) {
    
    
    console.log(err);
    return false;
  } else {
    
    
    console.log("读取文件成功!");
    console.log(data);
    // Console:
    // 读取文件成功!
    // <Buffer 48 65 6c 6c 6f 20 6a 73 6c 69 61 6e 67 e8 bf 99 e6 ae b5 e6 96 87 e6 9c ac e6 98 af e8 a6 81 e8 bf bd e5 8a a0 e7 9a 84 e5 86 85 e5 ae b9>
  }
})

// 6. fs.readdir 读取目录
fs.readdir('node_modules', (err, data) => {
    
    
  if(err) {
    
    
    console.log(err);
    return false;
  } else {
    
    
    console.log("读取目录成功!");
    console.log(data);
    // Console:
    // 读取目录成功!
    // [ '03_tool-multiply.js', 'jsliang-module' ]
  }
})

上記のように、ファイルの読み取りとディレクトリの読み取りに成功しました。
最後に、冒頭の目標を確認します。
1. fs.stat はファイルかディレクトリかを検出します。
2. fs.mkdir はディレクトリを作成します
。 3. fs.writeFile は書き込みファイルを作成します
。 4. fs.appendFile はファイルを追加します。
5. fs.readFile はファイルを読み取ります
6. fs.readdir ディレクトリを読み取ります
7. fs.rename 名前
を変更します8. fs.rmdir ディレクトリを削除します
9. fs.unlink ファイルを削除します
OK、名前を変更するだけです:
05_fs.js

let fs = require('fs');

// 7. fs.rename 重命名
fs.rename('index.js', 'jsliang.js', (err) => {
    
    
	if(err) {
    
    
		console.log(err);
		return false;
	} else {
    
    
		console.log("重命名成功!");
	}
})

もちろん、より強力な機能fs.renameがある次のようにします。

05_fs.js

let fs = require('fs');

// 7. fs.rename 重命名
fs.rename('jsliang.js', 'node_modules/jsliang.js', (err) => {
    
    
  if(err) {
    
    
    console.log(err);
    return false;
  } else {
    
    
    console.log("剪切成功!");
  }
})

すべて完了すると、ディレクトリは次のようになります。
ここに画像の説明を挿入

1.5fsの場合

前の章では、fsの。そこで、ここでは06_fsDemo.js
を使って小さなことをfsやって。

/**
 * 1. fs.stat 检测是文件还是目录
 * 2. fs.mkdir 创建目录
 * 3. fs.writeFile 创建写入文件
 * 4. fs.appendFile 追加文件
 * 5. fs.readFile 读取文件
 * 6. fs.readdir 读取目录
 * 7. fs.rename 重命名
 * 8. fs.rmdir 删除目录
 * 9. fs.unlink 删除文件
 */

// 1. 判断服务器上面有没有 upload 目录,没有就创建这个目录
// 2. 找出 html 目录下面的所有的目录,然后打印出来

let fs = require('fs');

// 图片上传
fs.stat('upload', (err, stats) => {
    
    
  // 判断有没有 upload 目录
  if(err) {
    
    
    // 如果没有
    fs.mkdir('upload', (error) => {
    
    
      if(error) {
    
    
        console.log(error);
        return false;
      } else {
    
    
        console.log("创建 upload 目录成功!");
      }
    })
  } else {
    
    
    // 如果有
    console.log(stats.isDirectory());
    console.log("有 upload 目录,你可以做更多操作!");
  }
})

// 读取目录全部文件
fs.readdir('node_modules', (err, files) => {
    
    
  if(err) {
    
    
    console.log(err);
    return false;
  } else {
    
    
    // 判断是目录还是文件夹
    console.log(files);

    let filesArr = [];

    (function getFile(i) {
    
    
      
      // 循环结束
      if(i == files.length) {
    
    
        // 打印出所有目录
        console.log("目录:");
        console.log(filesArr);
        return false;
      }

      // 判断目录是文件还是文件夹
      fs.stat('node_modules/' + files[i], (error, stats) => {
    
    

        if(stats.isDirectory()) {
    
    
          filesArr.push(files[i]);
        }

        // 递归调用
        getFile(i+1);
        
      })
    })(0)
  }
})

1.6 fsストリーム

私たちは次のfsストリーム。

// 新建 fs
const fs = require('fs');
// 流的方式读取文件
let fileReadStream = fs.createReadStream('index.js');
// 读取次数
let count = 0;
// 保存数据
let str = '';
// 开始读取
fileReadStream.on('data', (chunk) => {
    
    
  console.log(`${
      
      ++count} 接收到:${
      
      chunk.length}`);
  // Console:1 接收到:30
  str += chunk;
})
// 读取完成
fileReadStream.on('end', () => {
    
    
  console.log("——结束——");
  console.log(count);
  console.log(str);

  // Console:——结束——
  // 1
  // console.log("Hello World!");
})
// 读取失败
fileReadStream.on('error', (error) => {
    
    
  console.log(error);
})

ここではfscreateReadStreamモジュールを通じて読み取りストリームが作成され、ファイルindex.jsが読み取られるため、最終的に出力がコンソールに表示されます。

1 接收到:259
——结束——
1
console.log("尽信书,不如无书;尽看代码,不如删掉这些文件。");
console.log("尽信书,不如无书;尽看代码,不如删掉这些文件。");
console.log("尽信书,不如无书;尽看代码,不如删掉这些文件。");

このうち、console.log()の3行がindex.jsのテキスト内容です。
次に、卑猥な預金を試してください。

let fs = require('fs');
let data = 'console.log("Hello World! 我要存入数据!")';

// 创建一个可以写入的流,写入到文件 index.js 中
let writeStream = fs.createWriteStream('index.js');
// 开始写入
writeStream.write(data, 'utf8');
// 写入完成
writeStream.end();
writeStream.on('finish', () => {
    
    
  console.log('写入完成!');
  // Console:写入完成
});

これを開くとindex.js、内部のコンテンツが になっていることがわかりconsole.log("Hello World! 我要存入数据!")、ストリーム形式で読み取りおよび書き込み操作が行われています。

1.7 Webサーバーを作成する

ここでは、httpモジュール、urlモジュール、pathモ​​ジュール、fsモジュールを使用してWebサーバーを作成します。
Webサーバーとは何ですか?
Web サーバーとは、一般に Web サイト サーバーを指します。Web サーバーは、インターネット上の特定の種類のコンピュータ上に常駐するプログラムを指します。ブラウザなどの Web クライアントと同様にドキュメントを提供したり、世界中の人々がアクセスできる Web サイト ファイルを配置したりできます。訪問する世界のデータ ファイルを配置できます。現在、最も主流の Web サーバーは 3 つですApache 、Nginx 、IIS
次に、Node を使用して Web サービスを作成します。
ここに画像の説明を挿入
08_Webサービス.js

// 引入 http 模块
let http = require("http");

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

http.createServer((req, res) => {
    
    
  // 获取响应路径
  let pathName = req.url;

  // 默认加载路径
  if (pathName == "/") {
    
    
    // 默认加载的首页
    pathName = "index.html";
  }

  // 过滤 /favicon.ico 的请求
  if (pathName != "/favicon.ico") {
    
    
    // 获取 08_WebService 下的 index.html
    fs.readFile("./08_WebService/" + pathName, (err, data) => {
    
    
      if (err) {
    
    
        
        // 如果不存在这个文件
        
        console.log("404 Not Found!");
        fs.readFile('./08_WebService/404.html', (errorNotFound, dataNotFound) => {
    
    
          if(errorNotFound) {
    
    
            console.log(errorNotFound);
          } else {
    
    
            res.writeHead(200, {
    
    
              "Content-Type": "text/html; charset='utf-8'"
            });
            // 读取写入文件
            res.write(dataNotFound);
            // 结束响应
            res.end();
          }
        })
        return;
      } else {
    
    

        // 返回这个文件
        
        // 设置请求头
        res.writeHead(200, {
    
    
          "Content-Type": "text/html; charset='utf-8'"
        });
        // 读取写入文件
        res.write(data);
        // 结束响应
        res.end();
      }
    });
  }
}).listen(8080);

このようにして、ブラウザに入力するlocalhost:8080と。
ここに画像の説明を挿入
すると、index.htmlファイル。CSS も導入されていませんか?
したがって、次のステップはhtmlcss、 、およびjs08_WebService.js
を動的にロードすることです。

// 引入 http 模块
let http = require("http");

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

// 引入 url 模块
let url = require("url");

// 引入 path 模块
let path = require("path");

http.createServer((req, res) => {
    
    
  
  // 获取响应路径
  let pathName = url.parse(req.url).pathname;

  // 默认加载路径
  if (pathName == "/") {
    
    
    // 默认加载的首页
    pathName = "index.html";
  }

  // 获取文件的后缀名
  let extName = path.extname(pathName);

  // 过滤 /favicon.ico 的请求
  if (pathName != "/favicon.ico") {
    
    
    // 获取 08_WebService 下的 index.html
    fs.readFile("./08_WebService/" + pathName, (err, data) => {
    
    
      // 如果不存在这个文件
      if (err) {
    
    
        console.log("404 Not Found!");
        fs.readFile(
          "./08_WebService/404.html",
          (errorNotFound, dataNotFound) => {
    
    
            if (errorNotFound) {
    
    
              console.log(errorNotFound);
            } else {
    
    
              res.writeHead(200, {
    
    
                "Content-Type": "text/html; charset='utf-8'"
              });
              // 读取写入文件
              res.write(dataNotFound);
              // 结束响应
              res.end();
            }
          }
        );
        return;
      }
      // 返回这个文件
      else {
    
    
        // 获取文件类型
        let ext = getExt(extName);

        // 设置请求头
        res.writeHead(200, {
    
    
          "Content-Type": ext + "; charset='utf-8'"
        });
        // 读取写入文件
        res.write(data);
        // 结束响应
        res.end();
      }
    });
  }
}).listen(8080);

// 获取后缀名
getExt = (extName) => {
    
    
  switch(extName) {
    
    
    case '.html': return 'text/html';
    case '.css': return 'text/css';
    case '.js': return 'text/js';
    default: return 'text/html';
  }
}

このようにして、再度リクエストすると、ブラウザは次のようになります。
ここに画像の説明を挿入
 もちろん、上記では html、css、jsこれら 3 つのファイル タイプのみをシミュレートしましたが、さらに多くのファイル タイプをシミュレートする必要があります。

次に、さまざまなリクエスト応答に適応するようにjsファイルを:
08_WebService.js

// 引入 http 模块
let http = require("http");

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

// 引入 url 模块
let url = require("url");

// 引入 path 模块
let path = require("path");

http.createServer((req, res) => {
    
    
  
  // 获取响应路径
  let pathName = url.parse(req.url).pathname;

  // 默认加载路径
  if (pathName == "/") {
    
    
    // 默认加载的首页
    pathName = "index.html";
  }

  // 获取文件的后缀名
  let extName = path.extname(pathName);

  // 过滤 /favicon.ico 的请求
  if (pathName != "/favicon.ico") {
    
    
    // 获取 08_WebService 下的 index.html
    fs.readFile("./08_WebService/" + pathName, (err, data) => {
    
    
      // 如果不存在这个文件
      if (err) {
    
    
        console.log("404 Not Found!");
        fs.readFile(
          "./08_WebService/404.html",
          (errorNotFound, dataNotFound) => {
    
    
            if (errorNotFound) {
    
    
              console.log(errorNotFound);
            } else {
    
    
              res.writeHead(200, {
    
    
                "Content-Type": "text/html; charset='utf-8'"
              });
              // 读取写入文件
              res.write(dataNotFound);
              // 结束响应
              res.end();
            }
          }
        );
        return;
      }
      // 返回这个文件
      else {
    
    
        // 获取文件类型
        let ext = getExt(extName);
        console.log(ext);

        // 设置请求头
        res.writeHead(200, {
    
    
          "Content-Type": ext + "; charset='utf-8'"
        });
        // 读取写入文件
        res.write(data);
        // 结束响应
        res.end();
      }
    });
  }
}).listen(8080);

// 获取后缀名
getExt = (extName) => {
    
    
  // readFile 是异步操作,所以需要使用 readFileSync
  let data = fs.readFileSync('./08_ext.json');
  let ext = JSON.parse(data.toString());
  return ext[extName];
}

そこで、簡単な Web サーバーを作成しました。

1.8 ノンブロッキング I/O イベント駆動型

  Java、PHP、.NET などのサーバー側言語は、クライアント接続ごとに新しいスレッドを作成します。
  ノードはクライアント接続ごとに新しいスレッドを作成せず、1 つのスレッドのみを使用します。
ユーザーが接続すると内部イベントがトリガーされ、ノンブロッキング I/O とイベント駆動メカニズムを通じて、Node プログラムも巨視的に並列処理されます。
  Node を使用すると、8 GB のメモリを備えたサーバーで 40,000 を超える同時ユーザー接続を処理できます。
  この章では主に次のことを解決します。
  1. ノードのノンブロッキング I/O とは何ですか?
  2. ノード イベント モジュールとは何ですか?
  まず、通常のプログラミングでは、プログラムが 1 行ずつ希望どおりに記述できることを望みます:
09_io.js

console.log("1");

console.log("2");

console.log("3");

/**
 * Console:
 * 1
 * 2
 * 3
 */

   しかし、事態は裏目に出ました。
 いくつかの非同期メソッド (関数) を実行することがあります:
09_io.js

console.log("1");

// console.log("2");
let fs = require('fs');
getExt = () => {
    
    
  fs.readFile('08_ext.json', (err, data) => {
    
    
    console.log("2");
  })
}
getExt();

console.log("3");

/**
 * Console:
 * 1
 * 3
 * 2
 */

   上記のコードでは、 は Node.js の非同期関数fs.readFileである、したがって、プログラムは最初に 1 と 3 を実行し、次に のパート 2fs.readFileを実行します。

ここで、コードの一部の論理エラーが原因で Node が他のコードの実行を失敗させることはないことがわかります。

   これにより、ステップ 3 がステップ 2 の実行結果を取得できない可能性があるという問題が発生します。これはノードのノンブロッキング I/O ドライバーです。
   では、この問題を解決する方法はあるのでしょうか?
 いくつかの!
1. コールバック関数経由;
2. Nodeeventsモジュール。
09_io.js

let fs = require("fs");

getExt = (callback) => {
    
    
  fs.readFile('08_ext.json', (err, data) => {
    
    
    callback(data);
  })  
}

getExt( (result) => {
    
    
  console.log(result.toString());
})

コールバックを通じて、getExtの。

次に、Node のeventsモジュールこの非同期問題を解決します。

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

/**
 * Node 事件循环:
 * 1.Node 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高;
 * 2.Node 的每一个API都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发;
 * 3.Node 有多个内置的事件,我们可以通过引入events 模块,并通过实例化EventEmitter 类来绑定和监听事件。
 */

// 引入 events 模块
let events = require("events");
// 实例化事件对象
let EventEmitter = new events.EventEmitter();

getExt = () => {
    
    
  fs.readFile('08_ext.json', (err, data) => {
    
    
    // 将 data 广播出去
    EventEmitter.emit('data', data.toString());
  })  
};

getExt();

// 监听 data
EventEmitter.on('data', (ext) => {
    
    
  console.log(ext);
});

ここでは、フォームEventEmitter.onリッスンすることで、の内部実行結果を取得します。  このようにして、ノードの I/O イベントとモジュールdatagetExt
events

1.9 取得と投稿

ここに画像の説明を挿入
早速、コード
index.jsから始めましょう。

// 加载 http 模块
var http = require('http');

// 虚拟 SQL 读取出来的数据
var items = [];

// 创建 http 服务
http.createServer(function (req, res) {
    
    
  
  // 设置跨域的域名,* 代表允许任意域名跨域
  res.setHeader('Access-Control-Allow-Origin', '*');
  // 设置 header 类型
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  // 跨域允许的请求方式
  res.setHeader('Content-Type', 'application/json');

  // 判断请求
  switch (req.method) {
    
    
    
    // post 请求时,浏览器会先发一次 options 请求,如果请求通过,则继续发送正式的 post 请求
    case 'OPTIONS':
      res.statusCode = 200;
      res.end();
      break;
    
      // 如果是 get 请求,则直接返回 items 数组
    case 'GET':
      let data = JSON.stringify(items);
      res.write(data);
      res.end();
      break;
      
    // 如果是 post 请求
    case 'POST':
      let item = '';
      // 读取每次发送的数据
      req.on('data', function (chunk) {
    
    
        item += chunk;
      });
      // 数据发送完成
      req.on('end', function () {
    
    
        // 存入
        item = JSON.parse(item);
        items.push(item.item);
        // 将数据返回到客户端
        let data = JSON.stringify(items);
        res.write(data);
        res.end();
      });
      break;
  }
}).listen(3000)

console.log('http server is start...');


まずモジュールをロードしてhttpサービスを作成し、
次にクロスドメイン処理メソッドをクロスドメインを許可するように設定し、
その後リクエストの判定処理を行い、簡単なドリルを行うだけなので、getリクエストかpostリクエストかを判断するだけで、
最終的にリクエストの結果がクライアントに返されます。
上記ではバックエンド ノードをデプロイしましたが、フロントエンド ページはどのように実行するのでしょうか?
インデックス.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-⌃-Compatible" content="ie=edge">
  <title>Node Web</title>

</head>

<body>

  <div id="app">
    <h1>Todo List</h1>
    <ul>
      <li v-for="(item, index) in items" :key="index">{
   
   { item }}</li>
    </ul>
    <input type="text" v-model="item">
    <button @click="postApi">添加</button>
  </div>

  <!-- cdn 引用:Vue 和 Node -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  
  <script>
    new Vue({
      
      
      el: document.getElementById('app'),
      data: function () {
      
      
        return {
      
      
          items: [],
          item: '',
        }
      },
      created() {
      
      
        // 进入页面请求数据
        axios.get('http://localhost:3000/').then(res => {
      
      
          console.log("\n【API - get 数据】");
          console.log(res);
          this.items = res.data;
        }).catch(function (err) {
      
      
          console.log(err)
        })
      },
      methods: {
      
      
        // 点击按钮提交数据
        postApi() {
      
      
          axios.post('http://localhost:3000/', {
      
      
            item: this.item
          }).then(res => {
      
      
            console.log("\n【API - post 数据】")
            console.log(res);
            this.items = res.data;
          }).catch(function (err) {
      
      
            console.log(err)
          })
        }
      }
    })
  </script>
</body>

</html>

レイアウトは Vue で作成し、インターフェイスのリクエストは Axios で作成しました。以上でデータに対する操作が完了する。

1.9 ノードが MySQL に接続する

まず、視覚化ツールを使用してテーブルを設計します。

名前 タイプ 長さ
ID 整数 11 主キー
名前 可変長文字 255
可変長文字 255

次に、テーブルにデータを入力します。

ID 名前
1 ジスリアン 23
2 25

次に、ノードが MySQL に接続するためのパッケージをインストールします。

npm i mysql -D

次に、ノードのindex.jsを書きますindex.js

var mysql = require('mysql');
var connection = mysql.createConnection({
    
    
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'node'
});

connection.connect();

connection.query('SELECT * FROM user', function (error, results, fields) {
    
    
  if (error) throw error;
  console.log(results);
});

connection.end();

最後に、ノードindex.jsを通じてサービスを開きます。

[ RowDataPacket {
    
     id: 1, name: 'jsliang', age: '23' },
  RowDataPacket {
    
     id: 2, name: 'liang', age: '25' } ]

このようにして、MySQL への Node 接続が完了しました。

—————— 華麗な分割線——————

もちろん、追加、削除、変更、確認はバックエンドの基本的な操作ですので、ここで基本的な追加、削除、変更、確認機能は完了します。

まずディレクトリを見てください。
ここに画像の説明を挿入

  • 新しいテーブルフィールド
    add.js
var mysql = require('mysql');
var connection = mysql.createConnection({
    
    
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'node'
});

connection.connect();

let addSql = "INSERT INTO user(id,name,age) VALUES(0,?,?)";
let addSqlParams = ["jsliang", "23"];

connection.query(addSql, addSqlParams, function (err, res) {
    
    
  if (err) {
    
    
    console.log("新增错误:");
    console.log(err);
    return;
  } else {
    
    
    console.log("新增成功:");
    console.log(res);
  }
});

connection.end();

node add.jsデータベースにデータを直接追加するだけです。

  • テーブルフィールドの削除
    delete.js
// 连接 MySQL
var mysql = require('mysql');
// MySQL 的连接信息
var connection = mysql.createConnection({
    
    
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'node'
});

// 开始连接
connection.connect();

// 新增的 SQL 语句及新增的字段信息
var delSql = 'DELETE FROM user where id = 2';

// 连接 SQL 并实施语句
connection.query(delSql, function (err, res) {
    
    
  if (err) {
    
    
    console.log("删除错误:");
    console.log(err);
    return;
  } else {
    
    
    console.log("删除成功:");
    console.log(res);
  }
});

// 终止连接
connection.end();

  • テーブルフィールド
    update.jsを変更する
// 连接 MySQL
var mysql = require('mysql');
// MySQL 的连接信息
var connection = mysql.createConnection({
    
    
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'node'
});

// 开始连接
connection.connect();

// 新增的 SQL 语句及新增的字段信息
let updateSql = "UPDATE user SET name = ?,age = ? WHERE Id = ?";
let updateSqlParams = ["LiangJunrong", "23", 1];

// 连接 SQL 并实施语句
connection.query(updateSql, updateSqlParams, function (err, res) {
    
    
  if (err) {
    
    
    console.log("修改错误:");
    console.log(err);
    return;
  } else {
    
    
    console.log("修改成功:");
    console.log(res);
  }
});

// 终止连接
connection.end();

  • クエリテーブルフィールド
    read.js
// 连接 MySQL
var mysql = require('mysql');
// MySQL 的连接信息
var connection = mysql.createConnection({
    
    
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'node'
});

// 开始连接
connection.connect();

// 新增的 SQL 语句及新增的字段信息
let readSql = "SELECT * FROM user";

// 连接 SQL 并实施语句
connection.query(readSql, function (err, res) {
    
    
  if (err) throw err;
  console.log(res);
});

// 终止连接
connection.end();

以上で、NodeとMySQLの壁を突破し、データの追加、削除、変更、クエリを実現しました。

2.Web実戦 - 企業公式サイト

2.1 プログラミング環境

まず、フロントエンドの基本コードを見てみましょう

次に、バックエンドの機能分析を実行します。

  1. 伝言板。ユーザーが掲示板際には、ログインしているか否かを判断する必要がある。ユーザーがログインしていない場合はログイン、ユーザーがログインしている場合はメッセージ掲示板
    ページには2 つのインターフェイスがあります。
  • メッセージ内容の取得: すべてのメッセージ情報を返すgetMessageインターフェイス。期待されるメッセージがそれほど多くないため、ここではページング機能は実装されていません。必要な友人は、この機能を実装した後にページング インターフェイスを設計できます。
  • メッセージ コンテンツの送信:sendMessageインターフェイス、ユーザー名、ユーザー ID、およびメッセージ コンテンツをバックエンドに送信します。
  1. ログインページには、次のインターフェイスがあります。
    ログイン: loginインターフェイスを呼び出し、ユーザーが入力した名前とパスワードを送信します。
  2. 登録ページには、次のインターフェイスがあります。
    登録:registerインターフェイスを、ユーザーが入力した名前とパスワードを送信します。

これから、フロントエンドとバックエンドのインターフェイスの組み合わせを設計できます。

インターフェイスのドキュメント

インターフェース タイプ パラメータ 返されたメッセージ
getMessage: メッセージ情報を取得します 得る 参考文献なし n レコード: id (ユーザー ID)、user_name (ユーザー名)、user_message (ユーザー メッセージの内容)、time (メッセージ時刻)
sendMessage: メッセージを送信する 役職 id (ユーザーID)、user_name (ユーザー名)、user_message (ユーザーメッセージの内容) ステータス ステータス
login:ログイン 役職 id (ユーザーID)、user_name (ユーザー名)、user_password (ユーザーパスワード) ステータス ステータス
register:登録 役職 id (ユーザーID)、user_name (ユーザー名)、user_password (ユーザーパスワード) ステータス ステータス

最後に、MySQL データベースのテーブルを設計します。

user 表

名前 タイプ 長さ
ID 整数 11 主キー
ユーザー名 可変長文字 255
ユーザーのパスワード 可変長文字 255
時間 日付時刻

メッセージテーブル

名前 タイプ 長さ
ID 整数 11 主キー
ユーザー名 可変長文字 255
ユーザーのパスワード 可変長文字 255
時間 日付時刻

2.2 バックエンドインターフェース

実際の操作を行う前に、まずインターフェイスが記述できるかどうかを確認して、新しいtestフォルダー、その中に a と a を入れてテストしますindex.htmlindex.js

- text
 - index.html
 - index.js

まず最初に、2.1 で説明したインターフェイスに対してバックエンド インターフェイスを事前に設定します。

インデックス.js

// 连接 MySQL:先安装 npm i mysql -D
var mysql = require('mysql');
// MySQL 的连接信息
var connection = mysql.createConnection({
    
    
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'nodebase'
});
// 开始连接
connection.connect();

// 引入 http 模块:http 是提供 Web 服务的基础
const http = require("http");

// 引入 url 模块:url 是对用户提交的路径进行解析
const url = require("url");

// 引入 qs 模块:qs 是对路径进行 json 化或者将 json 转换为 string 路径
const qs = require("querystring");

// 用 http 模块创建服务
/**
 * req 获取 url 信息 (request)
 * res 浏览器返回响应信息 (response)
 */
http.createServer(function (req, res) {
    
    

  // 设置 cors 跨域
  res.setHeader("Access-Control-Allow-Origin", "*");
  // 设置 header 类型
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  // 跨域允许的请求方式
  res.setHeader('Content-Type', 'application/json');

  if (req.method == "POST") {
    
     // 接口 POST 形式

    console.log("\n【POST 形式】");

    // 获取前端发来的路由地址
    let pathName = req.url;

    console.log("\n接口为:" + pathName);

    // 接收发送过来的参数
    let tempResult = "";

    // 数据接入中
    req.addListener("data", function (chunk) {
    
    
      tempResult += chunk;
    });

    // 数据接收完成
    req.addListener("end", function () {
    
    

      var result = JSON.stringify(qs.parse(tempResult));
      console.log("\n参数为:");
      console.log(result);

      if (pathName == "/sendMessage") {
    
     // 提交留言信息

        console.log("\n【API - 提交留言信息】");

      } else if (pathName == "/login") {
    
     // 登录

        console.log("\n【API - 登录】");

      } else if (pathName == "/register") {
    
     // 注册

        console.log("\n【API - 注册】");

      }
      // 接口信息处理完毕
    })
    // 数据接收完毕

  } else if (req.method == "GET") {
    
     // 接口 GET 形式

    console.log("\n【GET 形式】");

    // 解析 url 接口
    let pathName = url.parse(req.url).pathname;

    console.log("\n接口为:" + pathName);

    if (pathName == "/getMessage") {
    
     // 获取留言信息

      console.log("\n【API - 获取留言信息】");

    } else if(pathName == "/") {
    
     // 首页
      res.writeHead(200, {
    
    
        "Content-Type": "text/html;charset=UTF-8"
      });

      res.write('<h1 style="text-align:center">jsliang 前端有限公司服务已开启!</h1><h2 style="text-align:center">详情可见:<a href="https://github.com/LiangJunrong/document-library/blob/master/other-library/Node/NodeBase.md" target="_blank">Node 基础</a></h2>');

      res.end();
    }

  }

}).listen(8888); // 监听的端口

// 获取当前时间
function getNowFormatDate() {
    
    
  var date = new Date();
  var year = date.getFullYear(); // 年
  var month = date.getMonth() + 1; // 月
  var strDate = date.getDate(); // 日
  var hour = date.getHours(); // 时
  var minute = date.getMinutes(); // 分
  var second = date.getMinutes(); // 秒
  if (month >= 1 && month <= 9) {
    
    
    month = "0" + month;
  }
  if (strDate >= 0 && strDate <= 9) {
    
    
    strDate = "0" + strDate;
  }
  // 返回 yyyy-mm-dd hh:mm:ss 形式
  var currentdate = year + "-" + month + "-" + strDate + " " + hour + ":" + minute + ":" + second;
  return currentdate;
}

req.methodロードされたインターフェースが に属しているか、フォームGETに属しているかを判断して、ロードされたインターフェースを決定します。POST

  • POST、それがメッセージの送信ログイン、または登録に属するかどうかを判断します。
  • GETではメッセージ情報を取得するかどうかを決定します。

同時に、MySQL 接続を定義しgetNowFormatDate、現在の時刻を取得します。形式は次のとおりです。2018-12-21 10:03:59

次に、インターフェイスがフロントエンド ページを通じて使用できるかどうかを示します。

インデックス.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>演示代码</title>
</head>

<body>
  <div>
    <label for="user">用户名</label><input type="text" id="user">
  </div>
  <div>
    <label for="password">&nbsp;&nbsp;&nbsp;</label><input type="password" id="password">
  </div>
  <div>
    <button id="register">注册</button>
  </div>

  <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
  <script>
    $(function () {
    
    
      // 测试 get 接口
      $.ajax({
    
    
        url: "http://localhost:8888/getMessage",
        type: "POST",
        data: {
    
    
          username: "jsliang"
        },
        success: function (res) {
    
    
          console.log(res);
        },
        error: function (err) {
    
    
          console.log(err);
        }
      })

      $("#register").click(function () {
    
    
        // 测试 post 接口
        $.ajax({
    
    
          url: "http://localhost:8888/login",
          type: "POST",
          data: {
    
    
            username: $("#user").val(),
            password: $("#password").val()
          },
          success: function (res) {
    
    
            console.log(res);
          },
          error: function (err) {
    
    
            console.log(err);
          }
        })
      })
    });
  </script>
</body>

</html>

最後にnode index.js、これを渡して開き、コンソールをindex.html介してインターフェースが正常かどう  かを確認しました。インターフェースが正常に調整されていることがわかり、データベースに接続してこれら 4 つのインターフェースを設計できます。F12

Nodeコードを更新するたびにnodeindex.jsを再起動するのが面倒だと感じる場合は、スーパーバイザを使用してNodeコードの変更を監視することができます。

2.3 登録機能

さて、模倣エンタープライズ Web サイトのページに戻り、インターフェイスを作成して Node のインターフェイスを強化する準備が整いました。
まず、フロントエンドとノード サービスを開始します。

  1. コマンドライン/ターミナルを開きます。
  2. フロントエンドを開く
    cd FrontEndCode
    live-server

インストールlive-server:npm i live-server -g

  1. オープンバックエンド
    cd NodeWeb
    supervisor index.js

スーパーバイザをインストールします: npm ivisor -g

次に、登録ページのクリック イベントを通じて呼び出しインターフェイスをトリガーします。

登録.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="keywords" content="前端,jsliang,bootstrap,企业建站">
  <meta http-equiv="description" content="jsliang 为你打造最好的企业服务">
  <link rel="shortcut icon" href="./images/favicon.ico" type="image/x-icon" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>注册-jsliang 前端有限公司</title>
  <link rel="stylesheet" href="./css/index.css">
  <link rel="stylesheet" href="./css/bootstrap.min.css">
</head>

<body>
  <!-- 省略 body 中代码,有需要的请前往第四章开头下载查看全部代码 -->

  <script src="./js/jquery-3.3.1.min.js"></script>
  <script src="./js/bootstrap.min.js"></script>
  <script src="./js/islogin.js"></script>
  <script>
    $(function () {
    
    
      $("#register-submit").click(function () {
    
    

        let userName = $("#userName").val();
        let userPassword = $("#userPassword").val();

        if (!userName) {
    
    
          alert("请输入用户名");
          $("#userName").focus();
        } else if (!userPassword) {
    
    
          alert("请输入密码");
          $("#userPassword").focus();
        } else if (userName.length > 10) {
    
    
          alert("请输入少于 10 位的用户名");
          $("#userName").focus();
        } else if (userPassword.length > 20) {
    
    
          alert("请输入少于 20 位的密码");
          $("#userPassword").focus();
        } else {
    
    

          // 如果用户输入的没毛病,那就加载接口
          $.ajax({
    
    
            url: "http://localhost:8888/register",
            type: 'post',
            dataType: 'json',
            data: {
    
    
              username: userName,
              password: userPassword
            },
            success: function (res) {
    
    
              console.log(res);
              if (res.code == "0") {
    
    
                alert("注册成功,前往登录!");
                window.location.href = "./login.html";
              }
            },
            error: function (err) {
    
    
              console.log(err.responseText);
              if (err.responseText == "注册失败,姓名重复!") {
    
    
                alert("用户名已被注册!");
              } else if (err.responseText == "注册失败,名额已满!") {
    
    
                alert("注册失败,名额已满!");
              } else if (err.responseText == "注册失败,密码为空!") {
    
    
                alert("注册失败,密码为空!");
              } else if (err.responseText == "注册失败,姓名过长!") {
    
    
                alert("注册失败,姓名过长!");
              } else if (err.responseText == "注册失败,密码过长!") {
    
    
                alert("注册失败,密码过长!");
              } else {
    
    
                alert("未知错误!");
              }
            }
          })
        }

      })
    })
  </script>
</body>

</html>

このようにして、ユーザーが「登録」ボタンをクリックすると、インターフェースを呼び出してデータをバックエンドに送信します。成功すると、ポップアップ ウィンドウが表示されてログイン ページにジャンプします。失敗すると、ポップアップ ウィンドウが表示され、ログイン ページにジャンプします。ウィンドウを開くとプロンプトが表示されます。
次にNode を書きますが、フロントエンドがインターフェースを呼び出した後、Node はこれら 2 つのパラメータが空かどうかを判断し、空でなければデータベースにデータを格納します。

インデックス.js

// ... 其他代码省略,请自行前往章节 2.2 后端接口 获取其他代码

if (pathName == "/sendMessage") {
    
     // 提交留言信息

  console.log("\n【API - 提交留言信息】");

} else if (pathName == "/login") {
    
     // 登录

  console.log("\n【API - 登录】");

} else if (pathName == "/register") {
    
     // 注册

  console.log("\n【API - 注册】");

  result = JSON.parse(result);

  let username = result.username; // 用户名
  let password = result.password; // 密码
  let time = getNowFormatDate(); // 时间

  if (!username) {
    
     // 用户名为空
    res.end("注册失败,用户名为空。");
    return;
  } else if (!password) {
    
     // 密码为空
    res.end("注册失败,密码为空!");
    return;
  } else if(username.length > 10) {
    
     // 姓名过长
    res.end("注册失败,姓名过长!");
    return;
  } else if(password.length > 20) {
    
     // 密码过长
    res.end("注册失败,密码过长!");
    return;
  } else {
    
    
    
    // 查询 user 表
    // 使用 Promise 的原因是因为中间调用了两次数据库,而数据库查询是异步的,所以需要用 Promise。
    new Promise( (resolve, reject) => {
    
    

      // 新增的 SQL 语句及新增的字段信息
      let readSql = "SELECT * FROM user";
      
      // 连接 SQL 并实施语句
      connection.query(readSql, function (error1, response1) {
    
    
        
        if (error1) {
    
     // 如果 SQL 语句错误
          throw error1;
        } else {
    
    
          
          console.log("\nSQL 查询结果:");

          // 将结果先去掉 RowDataPacket,再转换为 json 对象
          let newRes = JSON.parse(JSON.stringify(response1));
          console.log(newRes);

          // 判断姓名重复与否
          let userNameRepeat = false;
          for(let item in newRes) {
    
    
            if(newRes[item].user_name == username) {
    
    
              userNameRepeat = true;
            }
          }

          // 如果姓名重复
          if(userNameRepeat) {
    
    
            res.end("注册失败,姓名重复!");
            return;
          } else if(newRes.length > 300) {
    
     // 如果注册名额已满
            res.end("注册失败,名额已满!");
            return;
          } else {
    
     // 可以注册
            resolve();
          }
          
        }
      });

    }).then( () => {
    
    
      
      console.log("\n第二步:");
      
      // 新增的 SQL 语句及新增的字段信息
      let addSql = "INSERT INTO user(user_name,user_password, time) VALUES(?,?,?)";
      let addSqlParams = [result.username, result.password, time];

      // 连接 SQL 并实施语句
      connection.query(addSql, addSqlParams, function (error2, response2) {
    
    
        if (error2) {
    
     // 如果 SQL 语句错误
          console.log("新增错误:");
          console.log(error2);
          return;
        } else {
    
    
          console.log("\nSQL 查询结果:");
          console.log(response2);

          console.log("\n注册成功!");

          // 返回数据
          res.write(JSON.stringify({
    
    
            code: "0",
            message: "注册成功!"
          }));

          // 结束响应
          res.end();
        }
      });

    })
    // Promise 结束
  }
  // 注册流程结束
}

最後に、関数が成功したかどうかを確認します。

2.4 登録機能

上記で登録機能は完了しているので、クエリ部分はすでに一度試しているため、ログイン機能は比較的簡単に通過できます。

ログイン.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="keywords" content="前端,jsliang,bootstrap,企业建站">
  <meta http-equiv="description" content="jsliang 为你打造最好的企业服务">
  <link rel="shortcut icon" href="./images/favicon.ico" type="image/x-icon" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>登录-jsliang 前端有限公司</title>
  <link rel="stylesheet" href="./css/index.css">
  <link rel="stylesheet" href="./css/bootstrap.min.css">
</head>

<body>
  
  <!-- 代码省略,有需要的小伙伴请在第四章前言部分下载代码 -->

  <script src="./js/jquery-3.3.1.min.js"></script>
  <script src="./js/bootstrap.min.js"></script>
  <script src="./js/islogin.js"></script>
  <script>
    $(function () {
    
    
      $("#login-submit").click(function () {
    
    

        let userName = $("#userName").val(); // 用户名
        let userPassword = $("#userPassword").val(); // 密码

        if (!userName) {
    
    
          alert("请输入用户名");
          $("#userName").focus();
        } else if (!userPassword) {
    
    
          alert("请输入密码");
          $("#userPassword").focus();
        } else if (userName.length > 10) {
    
    
          alert("请输入少于 10 位的用户名");
          $("#userName").focus();
        } else if (userPassword.length > 20) {
    
    
          alert("请输入少于 20 位的密码");
          $("#userPassword").focus();
        } else {
    
    

          $.ajax({
    
    
            url: "http://localhost:8888/login",
            type: 'post',
            dataType: 'json',
            data: {
    
    
              username: userName,
              password: userPassword
            },
            success: function (res) {
    
    
              console.log(res);
              if (res.code == "0") {
    
    
                sessionStorage.setItem("id", res.data.id);
                sessionStorage.setItem("userName", res.data.userName);
                alert("登录成功!");
                window.location.href = "./messageBoard.html";
              } else if (res.code == "1") {
    
    
                alert("登录失败,密码错误!");
              }
            },
            error: function (err) {
    
    
              console.log(err.responseText);
              if (err.responseText == "不存在该用户!") {
    
    
                alert("不存在该用户!");
              } else if (err.responseText == "登录失败,用户名为空!") {
    
    
                alert("登录失败,用户名为空!");
              } else if (err.responseText == "登录失败,密码为空!") {
    
    
                alert("登录失败,密码为空!");
              } else if (err.responseText == "登录失败,姓名过长!") {
    
    
                alert("登录失败,姓名过长!");
              } else if (err.responseText == "登录失败,密码过长!") {
    
    
                alert("登录失败,密码过长!");
              } else {
    
    
                alert("未知错误!");
              }
            }
          })

        }

      })
    })
  </script>
</body>

</html>

フロントエンド コードを記述した後、ノード コードを編集します。

インデックス.js


// ... 其他代码省略,请自行前往章节 2.2 后端接口 获取其他代码

if (pathName == "/sendMessage") {
    
     // 提交留言信息

  console.log("\n【API - 提交留言信息】");

} else if (pathName == "/login") {
    
     // 登录

  console.log("\n【API - 登录】");

  result = JSON.parse(result);

  let username = result.username; // 用户名
  let password = result.password; // 密码

  if (!username) {
    
     // 用户名为空
    res.end("登录失败,用户名为空!");
    return;
  } else if (!password) {
    
     // 密码为空
    res.end("登录失败,密码为空!");
    return;
  } else if(username.length > 10) {
    
    
    res.end("登录失败,姓名过长!");
    return;
  } else if(password.length > 20) {
    
    
    res.end("登录失败,密码过长!");
    return;
  } else {
    
     
    
    // 新增的 SQL 语句及新增的字段信息
    let readSql = "SELECT * FROM user WHERE user_name  = '" + username + "'";

    // 连接 SQL 并实施语句
    connection.query(readSql, function (error1, response1) {
    
    
      if (error1) {
    
    
        throw error1;
      } else {
    
    
        if(response1 == undefined || response1.length == 0) {
    
     // 不存在用户
          res.end("\n不存在该用户!");
          return;
        } else {
    
     // 存在用户
          console.log("\n存在该用户!");

          let newRes = JSON.parse(JSON.stringify(response1));
          console.log(newRes);

          if(newRes[0].user_password == password) {
    
     // 密码正确
            // 返回数据
            res.write(JSON.stringify({
    
    
              code: "0",
              message: "登录成功!",
              data: {
    
    
                id: newRes[0].id,
                userName: newRes[0].user_name
              }
            }));

            res.end();
          } else {
    
     // 密码错误
            // 返回数据
            res.write(JSON.stringify({
    
    
              code: "1",
              message: "登录失败,密码错误!"
            }));

            res.end();
          }
          // 判断密码正确与否完毕
        }
        // 存在用户处理结束
      }
    });
  }
  // 登录步骤结束
} else if (pathName == "/register") {
    
     // 注册

  console.log("\n【API - 注册】");

}

非常にうまくいきました。フロントエンドとバックエンドが記述されました。関数が実装されているかどうかを確認します。

2.5 メッセージ機能

さて、残すはメッセージ機能だけですが、一気に上手にやっていきましょう!

メッセージボード.html

<!-- 留言板 -->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="keywords" content="前端,jsliang,bootstrap,企业建站">
  <meta http-equiv="description" content="jsliang 为你打造最好的企业服务">
  <link rel="shortcut icon" href="./images/favicon.ico" type="image/x-icon" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>留言板-jsliang 前端有限公司</title>
  <link rel="stylesheet" href="./css/index.css">
  <link rel="stylesheet" href="./css/bootstrap.min.css">
</head>

<body>
  
  <!-- 代码省略,基础代码请前往本章节前言下载 -->

  <script src="./js/jquery-3.3.1.min.js"></script>
  <script src="./js/bootstrap.min.js"></script>
  <script src="./js/islogin.js"></script>
  <script>
    $(function() {
    
    
      
      let userName = sessionStorage.getItem("userName");
      let userId = sessionStorage.getItem("id");
      
      // 查询留言板
      if(userName && userId) {
    
     // 如果有存储
        $.ajax({
    
    
          url: "http://localhost:8888/getMessage",
          type: 'get',
          dataType: 'json',
          success: function (res) {
    
    
            console.log(res);
            let li = ``;
            for(let item in res.data) {
    
    
              li = li + `
                <li>
                  <span class="text-warning font-bold">☆ </span>
                  <span class="user-message">${
      
      res.data[item].user_message}</span>
                  <span>—— </span>
                  <span class="user-name">${
      
      res.data[item].user_name} [${
      
      res.data[item].user_id}]</span>
                  <span class="message-time">${
      
      res.data[item].time}</span>
                </li>
              `;
            }
            $("#message-board-ul").append(li);
          },
          error: function (err) {
    
    
            console.log(err);
          }
        })
      } else {
    
     // 如果没有存储
        window.location.href = "../login.html";
      }

      // 提交留言
      $("#message-submit").click(function() {
    
    
        let messageText = $("#message").val()
        if(!messageText) {
    
    
          alert("留言内容不能为空");
        } else if(messageText.length > 140) {
    
    
          alert("留言长度不能超过 140 位!");
        } else {
    
    
          $.ajax({
    
    
            url: "http://localhost:8888/sendMessage",
            type: 'post',
            dataType: 'json',
            data: {
    
    
              userid: userId,
              username: userName,
              message: messageText
            },
            success: function (res) {
    
    
              console.log(res);
              if(res.code == "0") {
    
    
                alert("新增成功!");
                window.location.reload();
              }
            },
            error: function (err) {
    
    
              console.log(err);
              console.log(err.responseText);
              if (err.responseText == "登录失败,留言内容为空!") {
    
    
                alert("登录失败,留言内容为空!");
              } else if (err.responseText == "登录失败,字数超过限制!") {
    
    
                alert("登录失败,字数超过限制!");
              } else {
    
    
                alert("未知错误!");
              }
            }
          })
        }
      })

    })
  </script>
</body>

</html>

次に、Node バックエンドを記述します。

インデックス.js


// ... 其他代码省略,请自行前往章节 2.2 后端接口 获取其他代码

if (pathName == "/sendMessage") {
    
     // 提交留言信息

  console.log("\n【API - 提交留言信息】");

  result = JSON.parse(result);

  let id = result.userid; // id
  let userName = result.username; // 用户名
  let messageText = result.message; // 留言内容
  let time = getNowFormatDate(); // 时间

  if(!messageText) {
    
    
    res.end("登录失败,留言内容为空!");
    return;
  } else if(messageText.length > 140) {
    
    
    res.end("登录失败,字数超过限制!");
    return;
  } else {
    
    
    
    // 新增的 SQL 语句及新增的字段信息
    let addSql = "INSERT INTO message(user_message, user_id, user_name, time) VALUES(?, ?, ?, ?)";
    let addSqlParams = [messageText, id, userName, time];

    // 连接 SQL 并实施语句
    connection.query(addSql, addSqlParams, function (error1, response1) {
    
    
      if (error1) {
    
     // 如果 SQL 语句错误
        throw error1;
      } else {
    
    
        console.log("\n新增成功!");

        // 返回数据
        res.write(JSON.stringify({
    
    
          code: "0",
          message: "新增成功!"
        }));

        // 结束响应
        res.end();
      }
    })
  }

} else if (pathName == "/login") {
    
     // 登录

  console.log("\n【API - 登录】");

} else if (pathName == "/register") {
    
     // 注册

  console.log("\n【API - 注册】");

}



// ... 其他代码省略,请自行前往章节 2.2 后端接口 获取其他代码



if (pathName == "/getMessage") {
    
     // 获取留言信息

  console.log("\n【API - 获取留言信息】");

  // 解析 url 参数部分
  let params = url.parse(req.url, true).query;

  console.log("\n参数为:");
  console.log(params);

  // 新增的 SQL 语句及新增的字段信息
  let readSql = "SELECT * FROM message";

  // 连接 SQL 并实施语句
  connection.query(readSql, function (error1, response1) {
    
    
    if (error1) {
    
    
      throw error1; 
    } else {
    
    
      
      let newRes = JSON.parse(JSON.stringify(response1));
      console.log(newRes);

      // 返回数据
      res.write(JSON.stringify({
    
    
        code: "1",
        message: "查询成功!",
        data: newRes
      }));

      // 结束响应
      res.end();
    }
  });
  // 查询完毕
} else if(pathName == "/") {
    
     // 首页
  res.writeHead(200, {
    
    
    "Content-Type": "text/html;charset=UTF-8"
  });

  res.write('<h1 style="text-align:center">jsliang 前端有限公司服务已开启!</h1><h2 style="text-align:center">详情可见:<a href="https://github.com/LiangJunrong/document-library/blob/master/other-library/Node/NodeBase.md" target="_blank">Node 基础</a></h2>');

  res.end();
}

コードを入力した後、関数が実現されるかどうかを確認します。

要約すると、登録、ログイン、メッセージのすべての機能モジュールが完了しました。

3. ツールの統合

3.1 スーパーバイザ – ノードの変更を監視する

公式ウェブサイトに記載されているように、これは制御システムです。

1. プラグインをインストールします。npm i supervisor -g
2. ファイルを実行します。supervisor app.js
3. 確認して実行します。localhost:3000

通常node app.jsapp.jsの内容を変更した後、ノードのコマンド ラインを閉じて、再度実行する必要がありますnode app.js
を使用しsupervisorた後、app.jsの内容を変更します。 [保存] をクリックする限り、保存されたコードが有効になり、ノード コードの変更をリアルタイムで監視できます。

3.2 PM2 – ノードプロセス管理

PM2 はノード プロセス管理ツールであり、パフォーマンスの監視、自動再起動、負荷分散など、ノード アプリケーション管理の多くの面倒なタスクを簡素化するために使用でき、非常に使いやすいです。
以下は PM2 の入門編であり、基本的に PM2 の一般的に使用される機能と構成について説明しています。

  1. PM2 をグローバルにインストールします。npm i pm2 -g
  2. リスニングアプリケーション:pm2 start index.js
  3. すべてのプロセスを表示します。pm2 list
  4. プロセスを表示するには:pm2 describe App name/id
  5. プロセスを停止するには: pm2 stop App name/id例えば:

pm2 listビューへの最初のパス:

アプリ名 ID スターテス
索引 0 オンライン

pm2 stop indexまたはを実行するだけですpm2 stop 0

  1. すべてのプロセスを停止します。pm2 stop all
  2. プロセスを再起動します。pm2 restart App name/id
  3. プロセスを削除します。pm2 delete App name/id

上記のように、単一のプロセスを監視supervisorする、PM2複数のプロセスを監視することになります。

参考文献

Node - 0の基礎から実戦まで Enterprise公式サイトhttps://juejin.cn/post/6844903745755545614#Heading-12

おすすめ

転載: blog.csdn.net/qq_26780317/article/details/125870368