Create by jsliang on 2018-11-8 13:42:42
Recently revised in 2018-12-23 21:59:20php
Hello 小夥伴們,若是以爲本文還不錯,記得點個贊或者給個 star,大家的贊和 star 是我編寫更多更精彩文章的動力!GitHub 地址css
【2019-08-16】Hello 小夥伴們,因爲 jsliang 對文檔庫進行了重構,這篇文章的一些連接可能失效,而 jsliang 沒有精力維護掘金這邊的舊文章,對此深感抱歉。請須要獲取最新文章的小夥伴,點擊上面的 GitHub 地址,去文檔庫查看調整後的文章。html
不折騰的前端,和鹹魚有什麼區別前端
返回目錄vue
本文主要目的:node
798961601
中諮詢。返回目錄mysql
萬丈高樓平地起,地基還得本身起。jquery
返回目錄webpack
話很少說,先上代碼:ios
01_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); // 監聽的端口
複製代碼
那麼,上面代碼,咱們要怎麼用呢?
首先,將上面的代碼複製粘貼到 01_http.js
中。
而後,啓動 VS Code 終端:Ctrl + ~
。
接着,輸入 node 01_http.js
並回車。
最後,打開 localhost:3000
:
OK,搞定完事,如今咱們一一講解上面代碼:
var http = require("http");
複製代碼
/**
* req 獲取 url 信息 (request)
* res 瀏覽器返回響應信息 (response)
*/
http.createServer(function (req, res) {
// ... 步驟 3 代碼
}).listen(3000); // 監聽的端口
複製代碼
// 設置 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 服務,從而往頁面渲染頁面。至此,小夥伴們是否是也開啓了本身的 Node 之旅?
URL 模塊是什麼呢?
咱們在控制檯(終端)開啓 Node 模式,並打印出 url
來看一下:
好傢伙,它有 Url
、parse
、resolve
、resolveObject
、format
、URL
、URLSearchParams
、domainToASCII
、domainToUnicode
這麼多模塊。
那麼,這些模塊都有什麼用呢?
話很少說,先上代碼:
02_url.js
// 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 NodeJS</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
模塊更多的內容:
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]
}
*/
複製代碼
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/'
}
*/
複製代碼
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'
}
*/
複製代碼
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
複製代碼
resolve
的使用:console.log(url.resolve("http://www.baidu.com/jsliang", "梁峻榮"));
// Console:
// http://www.baidu.com/梁峻榮
複製代碼
固然,url
這裏咱們只講解了個入門,更多的還請看官網 API:url | Node.js v10.14.1 文檔
CommonJS 就是爲 JS 的表現來制定規範,由於 JS 沒有模塊系統、標準庫較少、缺少包管理工具,因此 CommonJS 應運而生,它但願 JS 能夠在任何地方運行,而不僅是在瀏覽器中,從而達到 Java、C#、PHP 這些後端語言具有開發大型應用的能力。
CommonJS 就是模塊化的標準,Node.js 就是 CommonJS(模塊化)的實現。
如今,咱們經過三種使用方式,來說解下 Node 中的模塊化及 exports/require 的使用。
咱們先查看下目錄:
方法一:
首先,咱們新建 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
。
第二步,咱們經過 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
的初次使用。
方法二:
當咱們模塊文件過多的時候,應該須要有個存放這些模塊的目錄,Node 就很靠譜,它規範咱們能夠將這些文件都放在 node_modules
目錄中(你們都放在這個目錄上,就不會有其餘亂七八糟的命名了)。
因此,咱們在 node_modules
中新建一個 03_tool-multiply.js
文件,其內容以下:
03_tool-multiply.js
var tools = {
multiply: (...numbers) => {
let sum = numbers[0];
for (let number in numbers) {
sum = sum * numbers[number];
}
return sum;
}
}
module.exports = tools;
複製代碼
在引用方面,咱們只須要經過:
// 若是 Node 在當前目錄沒找到 tool.js 文件,則會去 node_modules 裏面去查找
var tools2 = require('03_tool-multiply');
console.log(tools2.multiply(1, 2, 3, 4));
複製代碼
這樣,就能夠成功導入 03_tool-multiply.js
文件了。
方法三:
若是所有單個文件丟在 node_modules
上,它會顯得雜亂無章,因此咱們應該定義個本身的模塊:jsliang-module
,而後將咱們的 tools.js
存放在該目錄中:
jsliang-module/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');
去導入,會發現它報 error
了,因此,咱們應該在 jsliang-module
目錄下,經過下面命令行生成一個 package.json
PS E:\MyWeb\node_modules\jsliang-module> 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);
複製代碼
到此,咱們就經過三種方法,瞭解了各類 exports
和 require
的姿式以及 Node 模塊化的概念啦~
參考文獻:
Node 中除了它本身提供的核心模塊以外,還能夠自定義模塊,以及使用 第三方模塊。
Node 中第三方模塊由包組成,能夠經過包來對一組具備相互依賴關係的模塊進行統一管理。
那麼,假如咱們須要使用一些第三方模塊,應該去哪找呢?
那麼,npm 是啥?
npm 是世界上最大的開放源代碼的生態系統。咱們能夠經過 npm 下載各類各樣的包。
在咱們安裝 Node 的時候,它默認會順帶給你安裝 npm。
npm -v
:查看 npm 版本。npm list
:查看當前目錄下都安裝了哪些 npm 包。npm info 模塊
:查看該模塊的版本及內容。npm i 模塊@版本號
:安裝該模塊的指定版本。在平時使用 npm 安裝包的過程當中,你可能須要知道一些 npm 基本知識:
i
/install
:安裝。使用 install
或者它的簡寫 i
,都代表你想要下載這個包。uninstall
:卸載。若是你發現這個模塊你已經不使用了,那麼能夠經過 uninstall
卸載它。g
:全局安裝。代表這個包將安裝到你的計算機中,你能夠在計算機任何一個位置使用它。--save
/-S
:經過該種方式安裝的包的名稱及版本號會出如今 package.json
中的 dependencies
中。dependencies
是須要發佈在生成環境的。例如:ElementUI
是部署後還須要的,因此經過 -S
形式來安裝。--save-dev
/-D
:經過該種方式安裝的包的名稱及版本號會出如今 package.json
中的 devDependencies
中。devDependencies
只在開發環境使用。例如:gulp
只是用來壓縮代碼、打包的工具,程序運行時並不須要,因此經過 -D
形式來安裝。例子:
cnpm i webpack-cli -D
npm install element-ui -S
那麼,這麼多的 npm 包,咱們經過什麼管理呢?
答案是 package.json
。
若是咱們須要建立 package.json
,那麼咱們只須要在指定的包管理目錄(例如 node_modules
)中經過如下命名進行生成:
npm init
:按步驟建立 package.json
。npm init --yes
:快速建立 package.json
固然,由於國內網絡環境的緣由,有些時候經過 npm 下載包,可能會很慢或者直接卡斷,這時候就要安裝淘寶的 npm 鏡像:cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
本章節咱們講解下 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
// 1. fs.stat
let fs = require('fs');
fs.stat('index.js', (error, stats) => {
if(error) {
console.log(error);
return false;
} else {
console.log(stats);
/**
* Console:
* Stats {
* dev: 886875,
* mode: 33206,
* nlink: 1,
* uid: 0,
* gid: 0,
* rdev: 0,
* blksize: undefined,
* ino: 844424931461390,
* size: 284,
* blocks: undefined,
* atimeMs: 1542847157494,
* mtimeMs: 1543887546361.2158,
* ctimeMs: 1543887546361.2158,
* birthtimeMs: 1542847157493.663,
* atime: 2018-11-22T00:39:17.494Z,
* mtime: 2018-12-04T01:39:06.361Z,
* ctime: 2018-12-04T01:39:06.361Z,
* birthtime: 2018-11-22T00:39:17.494Z }
*/
console.log(`文件:${stats.isFile()}`);
// Console:文件:true
console.log(`目錄:${stats.isDirectory()}`);
// Console:目錄:false
return false;
}
})
複製代碼
經過 Console
打印出來的信息,咱們基礎掌握了 fs.stat
的做用。
而後,咱們嘗試經過 fs.mkdir
建立目錄:
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
,咱們發現目錄中多了一個 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
文件夾被刪除了。
接着,咱們經過 fs.writeFile
來建立寫入文件:
05_fs.js
// 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
變成了:
index.js
Hello jsliang這段文本是要追加的內容
複製代碼
在上面,咱們已經作了:新增、修改、刪除操做。那麼小夥伴必定很熟悉下一步驟是作什麼了:
fs.readFile
讀取文件fs.readdir
讀取目錄05_fs.js
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
刪除文件
很好,咱們就剩下重命名了:
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("剪切成功!");
}
})
複製代碼
OK,統統搞定,如今目錄變成了:
在上一章節中,咱們瞭解了 fs
的文件管理。
那麼,在這裏,咱們嘗試使用 fs
作點小事情:
06_fsDemo.js
/**
* 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)
}
})
複製代碼
話很少說,咱們瞭解下 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()
那三行就是 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! 我要存入數據!")
,依次,咱們經過流的形式進行了讀取和寫入的操做。
在這裏,咱們利用 http 模塊、url 模塊、path 模塊、fs 模塊建立一個 Web 服務器。
什麼是 Web 服務器?
Web 服務器通常指網站服務器,是指駐留於因特網上某種類型計算機的程序,能夠像瀏覽器等 Web 客戶端提供文檔,也能夠放置網站文件,讓全世界瀏覽;能夠放置數據文件,讓全世界下載。目前最主流的三個 Web 服務器是 Apache、Nginx、IIS。
下面,咱們使用 Node 來建立一個 Web 服務:
08_WebService.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
這三種文件類型而已,咱們須要模擬更多的文件類型:
代碼詳情請點擊上面的連接
複製代碼
在上面的 json
文件中,咱們定義了各類的文件類型,此刻文件目錄以下所示:
這時候,咱們須要修改下咱們的 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 服務器。
Java、PHP 或者 .NET 等服務端語言,會爲每個客戶端的鏈接建立一個新的線程。
Node 不會爲每個客戶鏈接建立一個新的線程,而僅僅使用一個線程。
當有用戶鏈接了,就會觸發一個內部事件,經過非租塞 I/O、事件驅動機制,讓 Node 程序宏觀上也是並行的。
使用 Node,一個 8GB 內存的服務器,能夠同時處理超過 4 萬用戶的鏈接。
在這一章節中,主要解決:
首先,在咱們正常編程中,咱們是但願程序可以一行一行按照咱們的意願編寫的:
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
*/
複製代碼
在上面代碼中,因爲 fs.readFile
是 Node 的異步函數。因此,程序先執行了 1 和 3,最後才執行 fs.readFile
的 2 部分。
在這裏,能夠看出 Node 不會由於一段代碼的邏輯錯誤,從而致使其餘代碼沒法運行。
這樣子,就致使了一個問題:步驟 3 可能拿不到步驟 2 的執行結果了!這就是 Node 的非租塞性 I/O 驅動。
那麼,咱們有沒有辦法解決這個問題呢?
有的!
events
模塊首先,咱們經過回調函數來解決這個異步問題:
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
經過監聽 data
的形式,獲取了 getExt
內部的執行結果。
如此,咱們就瞭解了 Node 的 I/O 事件及 events
模塊
話很少說,先上代碼:
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
請求。
最後,咱們將請求的結果返回給客戶端。
在上面,咱們進行了後端 Node 的部署,那麼前端頁面要怎麼作呢?
index.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 進行了接口的請求。從而完成了對數據的操做。
關於 MySQL 的安裝,能夠查看 jsliang 寫的:MySQL 安裝及圖形化工具
首先,咱們經過可視化工具進行表的設計:
名 | 類型 | 長度 | 鍵 |
---|---|---|---|
id | int | 11 | 主鍵 |
name | varchar | 255 | |
age | varchar | 255 |
而後,咱們進行表的填充:
id | name | age |
---|---|---|
1 | jslliang | 23 |
2 | 梁峻榮 | 23 |
接着,咱們安裝 Node 鏈接 MySQL 的包:
npm i mysql -D
複製代碼
再來,咱們編寫 Node 的 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();
複製代碼
最後,咱們經過 node index.js
,打開該服務:
[ RowDataPacket { id: 1, name: 'jsliang', age: '23' },
RowDataPacket { id: 2, name: '梁峻榮', age: '23' } ]
複製代碼
如此,咱們便完成了 Node 鏈接 MySQL。
———————華麗分割線———————
固然,增刪改查是後端的基本操做,因此在這裏,咱們能夠補全基本的增刪改查功能。
先看目錄:
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 的壁壘,實現了數據的增刪改查。
在進行代碼實戰的時候,咱們不少時候會遇到一些小事兒,例如:logo 製做、ico 製做、icon 挑選等……
下面這些都是 jsliang 平時碰到的,小夥伴有須要的能夠 mark 啦~
另外,因爲 HTML 與 CSS 沒什麼好講的,因此本章節的前提靜態頁面 jsliang 已經寫好了,小夥伴們在學習前能夠預先下載:
首先,咱們查看下咱們的前端基本代碼:地址
如上,咱們僅須要瞭解 FrontEndCode 目錄以及 NodeWeb 目錄便可,其餘目錄爲上面章節練習參考。
而後,咱們進行後端功能分析:
在 留言板頁面 中,存在兩個接口:
getMessage
接口,返回所有留言信息,因爲預計信息很少,故這裏不作分頁功能,有須要的小夥伴在實現完這個功能後,能夠進行分頁接口的設計。sendMessage
接口,將用戶名、用戶 id、留言內容發送給後端。login
接口,提交用戶填寫的姓名和密碼。register
接口,提交用戶填寫的姓名和密碼。由此,咱們能夠設計下先後端的接口結合:
接口文檔
接口 | 類型 | 參數 | 返回信息 |
---|---|---|---|
getMessage :獲取留言信息 |
get | 無參 | n 條記錄:id(用戶 id)、user_name(用戶名)、user_message(用戶留言內容)、time(留言時間) |
sendMessage :提交留言信息 |
post | id(用戶 id)、user_name(用戶名)、user_message(用戶留言內容) | status 狀態 |
login :登陸 |
post | id(用戶 id)、user_name(用戶名)、user_password(用戶密碼) | status 狀態 |
register :註冊 |
post | id(用戶 id)、user_name(用戶名)、user_password(用戶密碼) | status 狀態 |
最後,咱們進行 MySQL 數據庫的表設計:
user 表
名 | 類型 | 長度 | 鍵 |
---|---|---|---|
id | int | 11 | 主鍵 |
user_name | varchar | 255 | |
user_password | varchar | 255 | |
time | datetime |
message 表
名 | 類型 | 長度 | 鍵 |
---|---|---|---|
id | int | 11 | 主鍵 |
user_message | varchar | 255 | |
user_id | varchar | 255 | 外鍵 |
user_name | varchar | 255 | |
time | datetime |
在咱們進行實操以前,先確認咱們是否能寫接口,因此咱們能夠新建一個 test
文件夾,裏面放一個 index.html
以及一個 index.js
來測試一下。
- text
- index.html
- index.js
複製代碼
首先,咱們就 4.1 提到的接口,提早進行後端接口的設置:
index.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
而後,咱們經過一個前端頁面來演示咱們的接口是否能使用:
index.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
,經過 F12
控制檯查看咱們的接口是否正常:
能夠看到咱們的接口能正常調通,這樣咱們就能夠鏈接數據庫,進行這 4 個接口的設計了。
若是小夥伴們以爲每次更新 Node 代碼後,又要重啓一遍
node index.js
以爲麻煩,能夠經過supervisor
來監聽 Node 代碼的改動,supervisor
的安裝使用:supervisor
很好,咱們回到仿企業網站的頁面上,準備編寫接口以及豐富 Node 的接口。
首先,咱們開啓前端和 Node 服務:
打開命令行/終端
開啓前端
cd FrontEndCode
live-server
安裝
live-server
:npm i live-server -g
cd NodeWeb
supervisor index.js
安裝
supervisor
:npm i supervisor -g
而後,咱們在註冊頁面經過點擊事件來觸發調接口:
register.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 判斷這兩個參數是否爲空,若是不爲空,則將數據存儲到數據庫。
index.js
// ... 其餘代碼省略,請自行前往章節 4.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 結束
}
// 註冊流程結束
}
複製代碼
最後,咱們在查看下該功能是否成功:
在上面,咱們完成了註冊功能,那麼相對來講,登陸功能就容易通了,由於查詢部分咱們已經試過了一次。
login.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>
複製代碼
編寫完前端的代碼後,咱們進行 Node 代碼的編輯:
index.js
// ... 其餘代碼省略,請自行前往章節 4.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 - 註冊】");
}
複製代碼
很好,前端和後端都編寫完畢,是時候查驗下功能是否實現了:
如今,咱們就剩下留言功能了,一氣呵成作好它吧!
messageBoard.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 後端:
index.js
// ... 其餘代碼省略,請自行前往章節 4.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 - 註冊】");
}
// ... 其餘代碼省略,請自行前往章節 4.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();
}
複製代碼
敲完代碼再看下功能是否實現:
綜上,咱們完成了全部的功能模塊:註冊、登陸以及留言。
工欲善其事,必先利其器。
掌控好了工具,能夠方便你更快地進行開發。
正如其官網所說,它是一個進行控制系統:
npm i supervisor -g
supervisor app.js
localhost:3000
平時,咱們 node app.js
後,當咱們修改了 app.js
的內容,就須要關閉 node 命令行再執行 node app.js
。
而咱們使用 supervisor
後,咱們修改了 app.js
中的內容,只要點擊保存,便可生效保存後的代碼,實現實時監聽 node 代碼的變更。
關於這個工具,網上更詳細的攻略有:
PM2 是 Node 進程管理工具,能夠利用它來簡化不少 Node 應用管理的繁瑣任務,如性能監控、自動重啓、負載均衡等,並且使用很是簡單。
下面就對 PM2 進行入門性的介紹,基本涵蓋了 PM2 的經常使用的功能和配置:
npm i pm2 -g
pm2 start index.js
pm2 list
pm2 describe App name/id
pm2 stop App name/id
。例如:先經過
pm2 list
查看:
App name | id | status |
---|---|---|
index | 0 | online |
只須要執行 pm2 stop index
或者 pm2 stop 0
便可。
pm2 stop all
pm2 restart App name/id
pm2 delete App name/id
如上,若是說咱們的 supervisor
是監聽單個進程的話,那麼 PM2
就是監聽多個進程。
更多攻略:
在編寫這篇文章的過程當中,有一些參考資料是值得保留閱讀的:
經典,就是隨着時間流逝,它仍是那麼有參考價值。
Node 基礎模塊
Node 編寫接口
MySQL 學習
Node 鏈接數據庫
Node 仿 Express
關於線上部署及域名、服務器相關的配置,jsliang 在另一篇文章有所交代:雲服務器建站。
若是小夥伴須要訂購雲服務器來存放像 jsliang 我的網站類的靜態或者有 Node 後端的網頁,但殊不知道怎麼選擇,能夠加 jsliang QQ:1741020489
諮詢,下面是一些優惠推廣:
騰訊雲推廣:
新用戶點這裏:
購買雲服務器:
阿里雲推廣:
新用戶點這裏:
購買雲服務器:
購買企業級雲服務器:
綜上,搞定一切!
興許在前面代碼的摧殘下,能看到這裏的小夥伴已經寥寥無幾了,但我堅信我該交代的基本都交代了,不應交代的也交代了~
因此,若是小夥伴看完真以爲不錯,那就點個贊或者給個 star 吧!大家的贊和 star 是我編寫更多更精彩文章的動力!GitHub 地址
若是小夥伴看完這裏要評論的話,能夠加個暗語:Node 基礎,***
,這樣 jsliang 看到必回,哈哈~
so, that's all, thanks~
-----------------------
撰文不易,若是文章對小夥伴有幫助,但願小夥伴們給勤勞敲代碼、辛苦撰文的 jsliang 進行微信/支付寶打賞,大家的每一次打賞都是最好的鼓勵,謝謝~
jsliang 的文檔庫 由 梁峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可。
基於github.om/LiangJunron…上的做品創做。
本許可協議受權以外的使用權限能夠從 creativecommons.org/licenses/by… 處得到。