前書き:この記事は、Node 中間層の学習の実践に関連しています。元の記事Node-From 0 Basics to the Actual Enterprise Official Website
by jsliangを読むことをお勧めします。この記事を始める前に、まずノードの基本的な知識を理解しておくと、この記事の内容を理解するのに役立ちます。もちろん、この記事に従って、読みながら学習することもできます。(追記:借金返済を続けるノードシャオバイ╮(╯▽╰)╭)
この記事のハイライト:
- Node の基礎 – Node の基礎を学習して Node の基礎を築きます。
- ノード API – フロントエンド呼び出し用の API を提供するサービスを開きます。
- ノードは MySQL に接続します – npm を介して mysql をインストールし、データベースに接続します。
- Node Combat – 企業の公式 Web サイトは 0 から始まり、登録、ログイン、メッセージを残すことができる企業の公式 Web サイトを構築します。
- ノードの展開 – クラウド サーバーを展開して、Web サイトを誰でも利用できるようにする方法。
記事ディレクトリ
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.jsUrl
parse
resolve
resolveObject
format
URL
URLSearchParams
domainToASCII
domainToUnicode
// 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
ため、モジュールを作成します。url
http
// 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.js
、03_tool-add.js
、node_modules/03_tool-multiply.js
、node_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_modules
03_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.js
tools.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 を使用します。
fs.stat
ファイルかディレクトリかを検出します。fs.mkdir
ディレクトリを作成します。fs.writeFile
書き込みファイルを作成します。fs.appendFile
ファイルを追加するfs.readFile
ファイルを読み取ります。fs.readdir
ディレクトリを読み取ります。fs.rename
重命名 ;fs.rmdir
ディレクトリを削除します。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);
})
ここではfs
、createReadStream
モジュールを通じて読み取りストリームが作成され、ファイル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 も導入されていませんか?
したがって、次のステップはhtml
、css
、 、および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);
// 设置请求头
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 イベントとモジュールdata
getExt
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 プログラミング環境
まず、フロントエンドの基本コードを見てみましょう。
次に、バックエンドの機能分析を実行します。
- 伝言板。ユーザーが掲示板際には、ログインしているか否かを判断する必要がある。ユーザーがログインしていない場合はログイン、ユーザーがログインしている場合はメッセージ。掲示板
ページには2 つのインターフェイスがあります。
- メッセージ内容の取得: すべてのメッセージ情報を返す
getMessage
インターフェイス。期待されるメッセージがそれほど多くないため、ここではページング機能は実装されていません。必要な友人は、この機能を実装した後にページング インターフェイスを設計できます。 - メッセージ コンテンツの送信:
sendMessage
インターフェイス、ユーザー名、ユーザー ID、およびメッセージ コンテンツをバックエンドに送信します。
- ログインページには、次のインターフェイスがあります。
ログイン:login
インターフェイスを呼び出し、ユーザーが入力した名前とパスワードを送信します。 - 登録ページには、次のインターフェイスがあります。
登録: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.html
。index.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">密 码</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 のインターフェイスを強化する準備が整いました。
まず、フロントエンドとノード サービスを開始します。
- コマンドライン/ターミナルを開きます。
- フロントエンドを開く
cd FrontEndCode
live-server
インストール
live-server
:npm i live-server -g
- オープンバックエンド
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.js
、app.js
の内容を変更した後、ノードのコマンド ラインを閉じて、再度実行する必要がありますnode app.js
。
を使用しsupervisor
た後、app.js
の内容を変更します。 [保存] をクリックする限り、保存されたコードが有効になり、ノード コードの変更をリアルタイムで監視できます。
3.2 PM2 – ノードプロセス管理
PM2 はノード プロセス管理ツールであり、パフォーマンスの監視、自動再起動、負荷分散など、ノード アプリケーション管理の多くの面倒なタスクを簡素化するために使用でき、非常に使いやすいです。
以下は PM2 の入門編であり、基本的に PM2 の一般的に使用される機能と構成について説明しています。
- PM2 をグローバルにインストールします。
npm i pm2 -g
- リスニングアプリケーション:
pm2 start index.js
- すべてのプロセスを表示します。
pm2 list
- プロセスを表示するには:
pm2 describe App name/id
- プロセスを停止するには:
pm2 stop App name/id
。例えば:
pm2 list
ビューへの最初のパス:
アプリ名 | ID | スターテス |
---|---|---|
索引 | 0 | オンライン |
pm2 stop index
またはを実行するだけですpm2 stop 0
。
- すべてのプロセスを停止します。
pm2 stop all
- プロセスを再起動します。
pm2 restart App name/id
- プロセスを削除します。
pm2 delete App name/id
上記のように、単一のプロセスを監視supervisor
する、PM2
複数のプロセスを監視することになります。
参考文献
Node - 0の基礎から実戦まで Enterprise公式サイトhttps://juejin.cn/post/6844903745755545614#Heading-12