-
個人入門學習用筆記、不過多作為參考依據。如有錯誤歡迎斧正
-
目錄
簡書好像不支持錨點、復制搜索(反正也是寫給我自己看的)
- 瀏覽器
- javaScript
- 編程語言的能力
- Node
- 安裝(Mac)
- 使用
- Node---REPL環境
- 終端命令
- 異步操作
- I/O
- Node多線程
- NPM包管理工具
- nrm
- querystring字符串查詢模塊
- URL模塊
- 制作一個簡單的表單提交
- 文件操作
- 模板字符串
- HTTP
- http傳輸方式
- NET.socket
- 手動實現一個簡單的靜態資源管理服務
- exports&&require
- node_modules文件夾
- package.json
- Post請求處理(原生)
- 一些工具框架(庫)
-
瀏覽器
1、請求http地址(報文---傳輸的數據文檔)
瀏覽器的最大作用就是將一個url地址封裝成一個請求報文、并解析相應報文。
2、服務器返回的相應報文。
報文內容:
html/css/image = >渲染
js=>解釋(執行)js
-
javaScript
腳本語言
瀏覽器中運行
客戶端頁面交互實現運行在瀏覽器內核中的js引擎(engine)下
作用: 1、操作DOM(對DOM的修改、增刪改、注冊事件) 2、AJAX/跨域 3、BOM對象(頁面跳轉、歷史記錄、console.log()、alert()、window對象下的大部分子對象) 4、ECMAScript 不能進行的操作(由于js運行環境處于客戶端。影響安全性): 1、文件操作(文件和文件夾的CRUD增刪改查) 2、操作系統信息(版本號等)
-
編程語言的能力
所有編程語言本身只提供定義變量、函數、對象、流程控制、循環等操作
能力高低取決于運行該語言的平臺(環境)----瀏覽器
對于js來講。DOM/BOM等能力均由瀏覽器引擎提供。
java
既是語言、又是平臺。
java運行與java虛擬機(vm)平臺上(虛擬機本身可以跨操作系統運行)。C# 平臺:.net framework(Windows) 也可以運行于MONO這樣的平臺(Linux) PHP 既是語言、又是平臺
javaScript并不只能運行于瀏覽器
能運行在哪取決于環境有沒有特定的平臺
-
Node
- Node.js并不是一種語言。(使用v8引擎+js語法。V8:高效解析js、大部分為異步。node就是將V8中的一些功能移植到了服務器上)
- 一個js在服務端的運行平臺(runtime)
- 實際上就是JavaScript的虛擬機
- 是Node選擇了支持JavaScript、而不是JavaScript選擇了Node。
- 與PHP、JSP、Python等直接運行在服務器程序(Apache、Naginx、Tomcat、IIS)上的不同,Node.js跳過了HTTP服務器、不需要建立在任何服務器軟件之上。
- 不同于許多經典架構(LAMP=Linux(操作系統)+Apache(服務器)+MySQL(數據庫)+PHP(語言))、有著很大的不同、演變成LMP形式。并不存在web容器(根目錄)。?Node部署成功之后、并沒有運行服務器、但是Node線程卻擔當了服務器的作用。
特點
所謂特點、就是node.js如何解決服務器高性能瓶頸問題。
服務器語言(PHP、Java等)會為每一個客戶端建立一個新的線程(大約2MB)、理論上一個8GB內存的服務器可以連接4000個用戶。
Node只有一個線程、當用戶連接時、觸發一個內部事件。通過非阻塞I/O、事件驅動機制、讓node在宏觀上實現并行。使用node.js、一個8GB的服務器可以處理4萬用戶的鏈接。單線程:充分利用CPU.
提高鏈接上限、但是主線程崩潰會出現大面積崩潰。
非阻塞I/O(non-blocking I/O ):
在執行了I/O操作時、會將I/O操作移交磁盤進行物理并發、并立即執行其后面的代碼、I/O結束后以事件的形式返回并執行回調。
事件驅動(event-driven):
新用戶請求進入、或老用戶I/O異步回調返回時、會以事件形式加入事件環、等待調度(回調擁有更高的優先級)。
善于I/O、長連接、不善于計算:
擅長于業務調度(用戶表單收集--百度貼吧投訴、考試系統)、如果業務過渡占用CPU進行計算、實際上過多計算會阻塞線程。長連接也是業務調度。
作用:
1、web網站服務器(直接服務器)---比如淘寶
2、web網站請求包裝、服務器返回數據分發、渲染HTML頁面。(間接服務器)---Node的并發數、抗壓性高于傳統服務器平臺。比如天貓
https://github.com/NetEase/pomelo 網易開源游戲服務端
-
安裝(Mac)
條件:
1、xcode(因為內含GCC、python等)
xcode-select -p(可以檢查一下)
2、python(有了xcode基本python也具備了)
python -V(區分大小寫)
安裝Homebrew
ruby -v(安裝依賴ruby) www.brew.sh(Homebrew官網)
安裝Node.js
brew install node
版本控制
n 7.7.2(下載7.7.2版本的node.js)
- 安裝完成之后
n(上下鍵選擇本地版本。回車確定安裝)
-
使用
nodejs.org(官方教程)
你需要一個js文件控制服務器行為(例:)
//加載“http”模塊。由JavaScript編寫、負責創建web服務器、以及處理http相關任務 const http = require('http'); //加載其他js文件。無返回值、直接加載即可。 require('./vue.js') //獲取調用者對象 module.parent //ip、字符串 const hostname = '127.0.0.1'; //端口、數字 const port = 3005; //創建服務器 //http.createServer(function(回調函數));添加一個回調函數 //req含有請求相關的信息(來源url、請求類型) //res含有請求響應的內容 //1.返回文字等信息 const server = http.createServer(function(req, res){ res.statusCode = 200; //文本內容類型 res.setHeader('Content-Type', 'text/plain'); res.end('Hello World\n'); }); //2.返回一個html頁面 /*不同于Apache。node.js沒有web容器的概念、也就是沒有文件夾的概念*/ const server = http.createServer(function(req, res){ //node作為跨平臺文件、不支持同文件夾下直接index_01.html這種windows寫法、必須使用./index_01.html的linux寫法 fs.readFile('./index_01.html',(err,data) =>{ res.statusCode = 200; res.setHeader('Content-Type', 'text/html'); if (!err) { res.end(data); }else { res.end('html not found'); } }); }); //3.返回路由頁面 const server = http.createServer(function(req, res){ //http://127.0.0.1:3007/index_01.html req.url =/index_01.html //http://127.0.0.1:3007/index_02.html req.url =/index_02.html var url = req.url; //如果你愿意、也可以手寫url以隱藏文件路徑 //比如 if (req.url == '/lalala') url = '/index_01.html'; fs.readFile('.'+url,(err,data) =>{ res.statusCode = 200; res.setHeader('Content-Type', 'text/html'); if (!err) { res.end(data); }else { res.end('html not found'); } }); }); //讓服務器在端口監聽請求然后調用上面的函數 server.listen(port, hostname, function() { //成功啟動服務器監聽時、在控制臺打印 console.log(`Server running at http://${hostname}:${port}/`); });
res.end(data);是回調內必須實現的一個函數。
//ES6中匿名函數 function(a){} === (a) => {}
關于路由文件、有個重點
node.js在每一次讀取文件時、都會調取一遍createServer的回調
也就是說、內部的圖片也需要手動讀取。所以:var url = req.url; fs.readFile('.'+url,(err,data)
這樣的構成就非常重要。
否則就連圖片都需要手動指定文件路徑了。
當然。對于node.js。根目錄就是js文件所在目錄。啟動服務器
1.cd到js文件夾目錄下 2.node servers.js(啟動服務器文件 ) 3.control+c(關閉服務器)
帶參數運行腳本
node servers.js 123 asd 123可以通過process.argv[2]獲取 asd可以通過process.argv[3]獲取 argv[2]||'lalalalal' === argv[2]?argv[2]:'lalalala'
-
Node---REPL環境
//進入REPL環境(類似web控制臺、用來測試代碼模塊)
(控制臺)node
node --use_strict//嚴格模式--直接a = 10;之類會報錯
//退出REPS環境
.exit
上次取值替代符號
_ //代表上次所取的值
stdin&&stdout
stdin:采集用戶輸入
stdout:控制臺輸出(不帶\n的console.log())一個簡單的控制臺登錄demo
var q = '請輸入用戶名'; var users = { 'user1':'111', 'user2':'222', 'user3':'333' }; process.stdout.write(q+'\n'); var type = 0; var user; process.stdin.on('data',(input) => { //獲取keys的數組、并且查找是否含有input內容 input = input.toString().trim(); if (type === 0 ){ if(Object.keys(users).indexOf(input) === -1) { //用戶名不存在 process.stdout.write('用戶名不存在、'); process.stdout.write(q+':\n'); type = 0; }else { user = input; type = 1; process.stdout.write('請輸入密碼:\n'); } }else { var pwd = users[user]; if (input === pwd){ process.stdout.write('用戶'+user+'登錄成功\n'); type = 0; }else { process.stdout.write('密碼錯誤、請重新輸入密碼:\n') } } });
-
終端命令
輸出控制臺輸出+創建文件
echo 'aaa' >>1.txt
查看文件內容
cat 1.txt
創建一個目錄/文件
mkdir dirname
刪除文件/目錄
rm -rf dirname
-
異步操作
1、網絡請求
2、文件操作
-
I/O
input/output
-
Node多線程
1、Node平臺將一個任務聯通該任務的回調函數放到一個時間循環系統中。
2、事件循環高效的管理系統線程池、同事高效執行每一個任務。
3、當任務執行完成過后自動執行回調函數。Node將所有的阻塞操作、交付給內部線程池。
Node本身主線程主要就是不斷的“往返調度”(文件操作、網絡請求全部交由其他線程執行)。
Node可以充分利用單核CPU的優勢。
-
NPM包管理工具
npm(Node Pack Manager)
npm會隨著node的安裝、自動安裝
Nodejs本身是輕內核、不包含太多的功能。
在開發過程中可能需要引用大量的依賴包(再小的功能都有成熟的模塊)
個人開發者制作的功能擴展
https://www.npmjs.com/
require時、有限查找系統模塊。
然后才會查找項目中node_modules目錄;
查看所有依賴包npm ls
查看深度為0的根包
npm --depth 0
使用
npm install 包名稱
-
nrm
可以自動切換npm服務器指向
//安裝npm install -g nrm //查看所有可用指向 nrm ls //修改npm指向 nrm use taobao //檢測節點速度 nrm test
-
querystring字符串查詢模塊
querystring.parse字符串 =>字典
const querystring = require('querystring'); querystring.parse('foo=bar&abc=xyz&abc=123'); //return { foo: 'bar', abc: ['xyz', '123'] };
默認情況下,查詢字符串中的百分號編碼的字符會被認為使用了 UTF-8 編碼。 如果使用的是另一種字符編碼,則 decodeURIComponent 選項需要被指定,如以下例子:
querystring.parse('w=%D6%D0%CE%C4&foo=bar', null, null,{ decodeURIComponent: gbkDecodeURIComponent });
-
URL模塊
const url = require('url');
url.parse()可以將一個完整的url地址分為很多部分、例如:
var url = req.url; res.write('<h1>'+'url ---> '+url+'</h1>'); //url ---> /p/index_01.html?id=123 res.write('<h1>'+'host ---> '+urls.parse(url).host+'</h1>'); res.write('<h1>'+'port ---> '+urls.parse(url).port+'</h1>'); res.write('<h1>'+'path ---> '+urls.parse(url).path+'</h1>'); //path ---> /p/index_01.html?id=123 res.write('<h1>'+'pathname ---> '+urls.parse(url).pathname+'</h1>'); //pathname ---> /p/index_01.html res.write('<h1>'+'query ---> '+urls.parse(url).query+'</h1>'); query ---> id=123 //url.parse(urlstr,true).query 可以將參數轉化為json對象 var query = urls.parse(url,true).query; res.write('<h1>'+'id ---> '+ query.id +'</h1>'); //id ---> 123
-
制作一個簡單的表單提交
HTML
<form action="http://127.0.0.1:3010/" method="get"> <input type="text" name="name" />姓名<br> <input type="text" name="age" />年齡<br> <input type="radio" name="sex" value="男" />男 <input type="radio" name="sex" value="女" />女 <br> <input type="submit"> </form>
Node.js
const http = require('http'); var url = require('url'); var hostName = '127.0.0.1'; var port = 3010; http.createServer((req,res) => { var queryJson = url.parse(req.url,true).query; var name = queryJson.name; var age = queryJson.age; var sex = queryJson.sex; //支持中文顯示 res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" }); res.write(`<h1>服務器收到了表單請求</h1>`); res.write(`姓名:${name} 年齡:${age} 性別:${sex}`); res.end(); }).listen(port,hostName,()=>{ console.log(`成功監聽 http://${hostName}:${port}/`); });
-
文件操作
文件操作下、必須使用"絕對路徑(物理路徑)"
fs:
基礎的文件操作
//異步(options為編碼格式) fs.readFile(path[, options], (err, data) => { if (err) throw err; console.log(data); }); //同步(options為編碼格式) try { var data = fs.readFileSync(path[, options]) } catch(error){ }
如不聲明編碼格式。解析結果會一buffer(二進制緩沖區)格式輸出
流的形式讀取文件
const fs = require('fs'); const rr = fs.createReadStream('foo.txt'); var dara = ' '; rr.on('data', (chunk) => { //chunk為每次讀取出來的文件塊 (buffer---字節數組) //chunk.lenth data+=chunk.toString(); }); rr.on('end', () => { console.log('end'); });
buffer:
數據容器。將大文件整個放入緩沖區再分批寫入磁盤
//讀取 buffer.toString('utf8') //寫入(字符串) buffer.write(string[, offset[, length]][, encoding])
path:
提供和路徑相關的操作
//獲取文件名 path.basename(temp) //獲取路徑中目錄名稱 path.dirname(temp) //獲取不同系統中路徑分隔符、Windows是“;”Linux/MacOS是“:” path.delimiter //獲取環境變量 process.env.PATH.split(path.delimiter) //獲取路徑中后綴(擴展)名/包含"." path.extname(temp) //獲取文件信息對象.(文件目錄、文件名、擴展名等) var obj = path.parse(temp); //將對象路徑轉化成字符串 path.format(obj) //判斷是否為絕對路徑 path.isAbsolute(temp) //拼接路徑 path.join([path1],[path2],..) //根據當前系統常規化一個路徑 var a = path.normalize('C://dev\\abc//cba////1.txt'); console.log(a); //獲取to路徑相對于from的相對路徑 path.relative(from,to); //通過文件操作獲取目錄(允許從絕對路徑開始) path.resolve(__dirname,'..','./','./code'); //獲取當前操作系統中默認用的路徑成員分隔符.Windows“\” Linux、MacOS“/” path.sep //判斷操作系統win32:windows&&LinuxMacOS:posix //可以通過path.win32//posix改變node操作方式 console.log(path=== path.win32);
readline:
讀取大文本/歌詞等文件、一行一行讀
const readline = require('readline'); const fs = require('fs'); const rl = readline.createInterface({ input: fs.createReadStream('sample.txt') }); rl.on('line', (line) => { //確保每次返回一整行數據 //與createReadStream用流的形式返回buffer不用。 //readLIne直接返回字符串對象 console.log(`Line from file: ${line}`); });
const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: 'OHAI> ' }); rl.prompt(); //用戶輸入 rl.on('line', (line) => { switch (line.trim()) { case 'hello': console.log('world!'); break; default: console.log(`Say what? I might have heard${line.trim()}'`); break; } rl.prompt(); //用戶結束了輸入。 }).on('close', () => { console.log('Have a great day!'); process.exit(0); });
文件寫入
//只要是文件操作。fs以及path就是必須模塊 const fs = require('fs'); const path = require('path'); const data = {id:10}; //文件寫入時傳入對象data:結果為[object Object] //JSON.stringify(data)序列化:結果為{id:10} //JSON.parse(data)反序列化 //寫入、覆蓋 fs.writeFile(file, data[, options], callback); //追加 fs.appendFile(file, data[, options], callback); //文件流 var streamWriter = fs.createWriteStream(path.join(__dirname,'temp.txt')); streamWriter.write('hello1',() => { console.log('+1'); }); //同步書寫文件 fs.writeSync(fd, string[, position[, encoding]])
pipe()方式copy文件
readStream.pipe(writeStream); writeStream.on('pipe',(src) => { src===readStream; }
pipe()支持鏈式編程
判斷文件是否存在
fs.stat(path, callback(err, stats))
重命名文件或目錄
fs.rename(oldPath, newPath, callback); fs.renameSync(oldPath, newPath, callback);
刪除文件
fs.unlink(path, callback); fs.unlinkSync(path, callback)
創建文件夾(要求路徑必須存在)
fs.mkdir(path, callback);
監視文件變化
fs.watchFile(path.join(__dirname,'temp.txt'),(curr, prev) => { console.log(`previous:${prev.size}`); console.log(`current:${curr.size}`); });
fs-extra(第三方):
https://www.npmjs.com/package/fs-extra
擴展了文件拷貝、刪除等操作
-
模板字符串
通過不同的引號來包裹
' 普通字符串------` 模板字符串console.log(` 鵝,鵝,鵝, 曲項向天歌。 白毛浮綠水, 紅掌波清波。`); console.log(` this is ${nameHe}, this is ${nameShe}` , nameHe);
-
HTTP
客戶端輸入url
封裝成特定格式(http/https等)的請求報文
通過socket(連接方式)傳遞給服務端
服務端根據不同協議類型對報文進行解析
。。。。。
客戶端接收到服務端返回的報文并加以解析
客戶端渲染內容到頁面當中
-
http傳輸方式
PUT:傳輸文件(<b>增</b>)
DELETE:刪除文件(<b>刪</b>)
POST:傳輸實體主題(<b>改</b>)
Get:獲取資源(<b>查</b>)
HEAD:獲得報文首部
OPTIONS:詢問支持的方法
TRACE:追蹤路徑
CONNECT:要求用隧道協議鏈接代理
LINK:建立和資源之間聯系(1.1已廢棄)
UNLINK:斷開連接關系(1.1已廢棄)
-
NET.socket
一個簡單的socketdemo
服務端
const net = require('net'); //創建socket服務器 var server = net.createServer(socketConnect); // 當有客戶端與服務器連接時、觸發 function socketConnect (socket) { //自己的ip var myIp = socket.address().address; //其他人的ip var userip = socket.remoteAddress; var clientIp = socket.address().address; console.log(`被鏈接from:${userip}`); //監聽socket數據流 socket.on('data',(chunk) => { process.stdout.write(`客戶端輸入:${chunk.toString()}`); // console.log(`客戶端輸入:${chunk.toString()}`); }); socket.on('end',() => { console.log('客戶端斷開連接'); }); //通過socket對象向另一端通信 socket.write('hello kirito!') } // 讓socket服務器監聽端口 //post傳入0則會由系統分配空閑端口 var post = 2080; server.listen(post,(err) =>{ //監聽成功回調 if (err){ //通常是端口被其他對象占用ing throw err; } console.log(`服務端開啟,監聽:${post}端口`); });
客戶端
const net = require('net'); //與服務端socket作為參數可返回多個不同。客戶端只返回一個socket對象. const socket = net.createConnection({ port: 2080 }, () => { //'connect' listener console.log('連接成功!'); }); //數據接收監聽 socket.on('data', (data) => { console.log(`服務端返回${data.toString()}`); process.stdout.write('client:'); // socket.end(); }); //鏈接斷開監聽 socket.on('end', () => { console.log('disconnected from server'); }); //監聽控制臺輸入 process.stdin.on('data',input =>{ process.stdout.write('client:'); if (input.toString().trim() === 'exit') { socket.end(); return; } socket.write(input.toString()); });
-
手動實現一個簡單的靜態資源管理服務
const http = require('http'); const url = require('url'); const fs = require('fs'); const path = require('path'); const post = 3000; const host = '127.0.0.1'; var mimeJSON; http.createServer((req,res) => { //拿到路徑 var pathName = url.parse(req.url).pathname; console.log(pathName); if (pathName.length == 1){ pathName = '/index.html'; } var extname = path.extname(pathName); //讀取文件 fs.readFile('./static/'+pathName,(err,files) => { if (err){ res.writeHead(404, { "Content-Type": "text/html;charset=utf-8" }); fs.readFile('./static/'+'404.html',(err,files) => { res.end(files); }); }else { getMine(extname,(mime) => { //MIME類型 //網頁:text/html //jpg:image/jpg res.writeHead(200, { "Content-Type":mime }); res.end(files); }); } }); }).listen(post,host,() => { console.log(`成功監聽${host}:${post}`); }); function getMine(extname,callback) { var mime; if (!mimeJSON) { fs.readFile('./static/mime.json',(err,data) => { if (err) { mimeJSON = {'aaa': 'dddd'}; }else { mimeJSON = JSON.parse(data); } mime = mimeJSON[extname] || 'text/plain'; console.log('11'+mime); callback(mime) }) }else { mime = mimeJSON[extname] || 'text/plain'; console.log('22'+mime); callback(mime); } }
exports&&require
(在前端中、js與js文件通過html文件相互聯系。
而在node.js中、二者則通過exports與require相互聯系)
暴露函數、變量
當需要從A.js引用B.js內部的變量、函數時。
必須在B中使用exports對象進行暴露。
A中使用require命令引用B.js文件B
var msg = '你好'; exports.msg = msg;
A
//將foo.exports解固成頂層變量 const foo = require('./foo.js'); console.log(foo.msg);
暴露類、構造函數
B
function People(name,sex,age) { this.name = name; this.sex = sex; this.age = age; } People.prototype.sayHello = function () { console.log(this.name+this.sex+this.age); } //此時People就被視為構造函數、可以用new來實例化 module.exports = People;
A
var People = require('./people.js'); var xiaoming = new People('小明','男','12歲'); xiaoming.sayHello();
exports&&module.exports
module.exports
- 將模塊的require變成一個函數、或者任意類型的對象。
module.exports = function(name, age) { this.name = name; this.age = age; this.about = function() { console.log(this.name +' is '+ this.age +' years old'); }; }; var Rocker = require('./rocker.js'); var r = new Rocker('Ozzy', 62); r.about(); // Ozzy is 62 years old
exports
- exports.xxx= xxx本質上等于為module.exports添加新的方法。或者屬性
- 如果你已經實現了module.exports、那么之后的 exports.xxx將會失效、不會動態添加.
如果你想你的模塊是一個特定的類型就用Module.exports。如果你想的模塊是一個典型的“實例化對象”就用exports。
-
node_modules文件夾
假如 /home/ry/projects/foo.js 調用了
require('bar.js')
那么node查找的位置依次為:
/home/ry/projects/node_modules/bar.js /home/ry/node_modules/bar.js /home/node_modules/bar.js
假如 /home/ry/projects/foo.js 調用了
require('bar')
1、那么node將會先查找文件:
/home/ry/projects/node_modules/bar/package.json
關于package.json、每一個模塊文件夾的根文件中推薦都寫一個package.json文件(文件名固定)。node將自動讀取內部配置。
{ "name": "kiritoVar", "version": "0.0.1", "main":"ffff.js" }
2、然后node將會查找文件:
/home/ry/projects/node_modules/bar.js
3、若沒有找到在繼續查找文件
/home/ry/projects/node_modules/bar/index.js
package.json
- 在你的項目完成之后、可以用npm為自己的項目創建一個package.json
控制臺$ npm init 會出現如下引導(均可不填) package name: (beginning) beginning //項目名稱 version: (1.0.0) //版本 description: my node demo//項目說明 entry point: (demo_01.js) url_demo.js//入口 test command: //測試 git repository: //git倉庫 keywords: suibian//標簽、關鍵詞 author: kritio_song//作者 license: (ISC) ISC//版權
然后將會生成一個package.json文件
其中最重要的一點、他將會含有一個dependencies字段"dependencies": { "date": "^1.0.2" 其中'^',表示固定這個數字 "^1.^0.2"就表示固定為1.0.x這樣 },
dependencies下、記錄著此項目所有引用的第三方模塊、以及node_modules文件夾下你自己創建的模塊
作用
在項目目錄下 $ npm install
將會檢測所有dependencies下的依賴、并且自動安裝
Post請求處理
原生
if (req.url == '/dopost' && req.method.toLowerCase() == 'post'){ var allData = ''; //為了防止參數過多影響線程利用、node讀取參數的方式是分塊讀取。參數過多時、可能會多次回調 req.addListener('data',(chunk) =>{ allData += chunk; }); //讀取完畢 req.addListener('end',(chunk) =>{ console.log(allData.toString()); //輸出foo=bar&abc=xyz&abc=123 //可以使用querystring模塊轉義 querystring.parse(str)字符串 =>字典 res.end(allData); }); }
原生處理post請求、需要兩個監聽。并且文件上傳需要特殊處理
formidable
const http = require('http'); const path = require('path'); const fs = require('fs'); const formidable = require('formidable'); const post = 8080; const host = '127.0.0.1'; http.createServer((req,res) => { if (req.url == '/dopost' && req.method.toLowerCase() == 'post'){ var form = new formidable.IncomingForm(); //設置文件上傳存放地址 form.uploadDir = __dirname+"/fileDir"; //執行里面的回調函數時、表單已經接收完畢 form.parse(req, function(err, fields, files) { //所有的文本域、單選框,都在fields存放 //所有的文件域、都在files存放 console.log(err); console.log(fields); console.log(files); if (files){ var extname = path.extname(files.file.name); var random = parseInt(Math.random() * 999999 + 100000); var dir = form.uploadDir; var timestamp=new Date().getTime(); var oldName = files.file.path; var newName = dir+'/'+timestamp+random+extname; //修改文件名以及后綴 fs.rename(oldName,newName,()=>{ console.log(`renameed to ${newName}`); }) } res.end('succes'); }); } }).listen(post,host,() =>{ console.log(`成功監聽${host}:${post}`) });
formidable只能接收表單形式提交上來的post參數。
-
模板引擎
EJS(通過字符串進行邏輯替換)
- Embedded JavaScript templates
- 后臺的一個模板引擎
- 現在很少用、基本都是前端采用模板拼接(比如vue.js)
const ejs = require('ejs'); var string = '我買了一個iphone<%= a%>s'; var data = { a : 6 }; var html = ejs.render(string,data); console.log(html);
也可以直接替換html文件中的模板標記
node文件中:
const fs = require('fs'); const ejs = require('ejs'); const http = require('http'); http.createServer((req,res) => { fs.readFile('./view/index.ejs',(err ,data ) => { var template = data.toString(); var dictionary = { a:6, news:['第一個','第二個','第三個'] }; var html = ejs.render(template,dictionary); res.writeHead(200, { "Content-Type":'text/html' }); res.end(html); }); }).listen(3000,'127.0.0.1',() =>{ console.log('監聽成功'); });
html文件中:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" type="text/css" href="css/css_01.css"> </head> <body> <h1>好高興啊、我今天買了一個iphone<%= a%>s</h1> <ul> <% for (var i = 0 ; i< news.length ; i ++){ if(news){ %> <li><%= news[i]%></li> <% } } %> </ul> </body> </html>
<% %>之中支持所有js語法(for if等)
include引用
<% include nav.ejs %>
-
圖片處理
-
webSocket
使用SocketIO模塊
- app.js
/** * Created by kiritoSong on 17/9/29. */ var http = require('http'); var fs = require('fs'); var server = http.createServer(function (req, res) { if (req.url == '/'){ fs.readFile('./index.html',function (err,data) { res.end(data); }) } }); //將server變成socket //http://127.0.0.1:3000/socket.io/socket.io.js 會是一個文件地址 var io = require('socket.io')(server); //監聽鏈接事件 io.on('connection',function (socket) { socket.on('提問',function (msg) { console.log('客戶端提問:'+msg); socket.emit('回答',['吃了','還是沒吃']); }) socket.on('廣播',function (msg) { //broadcast 廣播 socket.broadcast.emit('有人問我'+msg); console.log('客戶端提問:'+msg); //io.emit可以向所有連接廣播 io.emit('回答',['吃了','還是沒吃']); }) }); server.listen(3000);
- index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Socket</title> </head> <body> <ht>index頁面</ht> <script src="/socket.io/socket.io.js" type="text/javascript"></script> <script type="text/javascript"> //客戶端socket、與服務端相互對應 var socket = io(); socket.emit('提問','你吃了么'); socket.on('回答',function (msg) { for (var i = 0 ; i < msg.length ; i++ ){ console.log('服務器回答'+i+'::'+msg[i]); } }) </script> </body> </html>
WechatIMG8.jpegWechatIMG10.jpeg
socket.emit('k',msg)負責發送
socket.on('k',msg)負責監聽
服務器&&客戶端均是
express搭配socket.io
-
一些工具框架(庫)
nodemon
一個可以監聽node文件改變、并且重新開啟node文件的工具
webSocket(瀏覽器不支持socket則自動模擬長輪詢)