JS是腳本語言,腳本語言都須要一個解析器才能運行。對於寫在HTML頁面裏的JS,瀏覽器充當瞭解析器的角色。而對於須要獨立運行的JS,NodeJS就是一個解析器。php
每一種解析器都是一個運行環境,不但容許JS定義各類數據結構,進行各類計算,還容許JS使用運行環境提供的內置對象和方法作一些事情。例如運行在瀏覽器中的JS的用途是操做DOM,瀏覽器就提供了document
之類的內置對象。而運行在NodeJS中的JS的用途是操做磁盤文件或搭建HTTP服務器,NodeJS就相應提供了fs
、http
等內置對象。css
官網APIhtml
中文翻譯java
在引入
TypedArray
以前,JavaScript 語言沒有用於讀取或操做二進制數據流的機制。Buffer
類是做爲 Node.js API 的一部分引入的,用於在 TCP 流、文件系統操做、以及其餘上下文中與八位字節流進行交互。nodeBuffer對象是Node處理二進制數據的一個接口。它是Node原生提供的全局對象,能夠直接使用,不須要require(‘buffer’),個人理解其實buffer就是個字節數組。linux
write() 向buffer對象中寫入內容web
slice() 截取新的buffer對象express
toString() 把buf對象轉成字符串json
toJson() 把buf對象轉成json形式的字符串windows
toJSON方法不須要顯式調用,當JSON.stringify方法調用的時候會自動調用toJSON方法
path
模塊提供用於處理文件路徑和目錄路徑的實用工具。 它可使用如下方式訪問:
const path = require('path');
const path = require('path'); console.log(path) // 結果: // { resolve: [Function: resolve], // normalize: [Function: normalize], // isAbsolute: [Function: isAbsolute], // join: [Function: join], // relative: [Function: relative], // toNamespacedPath: [Function: toNamespacedPath], // dirname: [Function: dirname], // basename: [Function: basename], // extname: [Function: extname], // format: [Function: format], // parse: [Function: parse], // sep: '\\', // delimiter: ';', // win32: [Circular], // posix: // { resolve: [Function: resolve], // normalize: [Function: normalize], // isAbsolute: [Function: isAbsolute], // join: [Function: join], // relative: [Function: relative], // toNamespacedPath: [Function: toNamespacedPath], // dirname: [Function: dirname], // basename: [Function: basename], // extname: [Function: extname], // format: [Function: format], // parse: [Function: parse], // sep: '/', // delimiter: ':', // win32: [Circular], // posix: [Circular], // _makeLong: [Function: toNamespacedPath] }, // _makeLong: [Function: toNamespacedPath] }
console.log(path.basename('/foo/bar/baz/asdf/quux.html')); // 返回: 'quux.html' console.log(path.basename('/foo/bar/baz/asdf/quux.html', '.html')); // 返回: 'quux'
console.log(__dirname); // 返回 此文件目錄的絕對路徑C:\Users\xiaox\Desktop\code console.log(__filename) // 返回 此文件的絕對路徑C:\Users\xiaox\Desktop\code\1.js console.log(path.dirname('/abc/qqq/www/abc')); // 返回 /abc/qqq/www console.log(path.dirname('/abc/qqq/www/abc.txt')); // 返回 /abc/qqq/www
console.log(path.extname('index.html')); // 返回 .html
path.format(pathObject) obj->string
let objpath = { root: 'C:\\', dir: 'C:\\Users\\xiaox\\Desktop\\code', base: '1.js', ext: '.js', name: '1' }; console.log(path.format(objpath)); // 返回C:\Users\xiaox\Desktop\code\1.js
當爲
pathObject
提供屬性時,注意如下組合,其中一些屬性優先於另外一些屬性:
- 若是提供了
pathObject.dir
,則忽略pathObject.root
。- 若是
pathObject.base
存在,則忽略pathObject.ext
和pathObject.name
。
path.parse(path) string->obj
console.log(path.parse(__filename)); /* { root: 'C:\\', dir: 'C:\\Users\\xiaox\\Desktop\\code', base: '1.js', ext: '.js', name: '1' } */
console.log(path.isAbsolute('/foo/bar')); // 返回true console.log(path.isAbsolute('C:/foo/..')); // 返回true
(…表示上層路徑;.表示當前路徑),在鏈接路徑的時候會格式化路徑
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // 返回: '/foo/bar/baz/asdf' path.join('foo', {}, 'bar'); // 拋出 'TypeError: Path must be a string. Received {}'
console.log(path.normalize('/foo/bar//baz/asdf/quux/..')); // 返回: '/foo/bar/baz/asdf' console.log(path.normalize('C:\\temp\\\\foo\\bar\\..\\')); // 返回: 'C:\\temp\\foo\\'
console.log(path.relative('/data/orandea/test/aaa','/data/orandea/impl/bbb')); // 返回: '../../impl/bbb' console.log(path.relative('C:\\orandea\\test\\aaa','C:\\orandea\\impl\\bbb')); // 返回: '..\\..\\impl\\bbb'
給定的路徑序列從右到左進行處理,每一個後續的 path
前置,直到構造出一個絕對路徑
path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'); // 若是當前工做目錄是 /home/myself/node, // 則返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'
console.log(path.delimiter);//表示路徑分隔符(windows是\ Linux是/) 在 POSIX 上: console.log(process.env.PATH); // 打印: '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin' process.env.PATH.split(path.delimiter); // 返回: ['/usr/bin', '/bin', '/usr/sbin', '/sbin', '/usr/local/bin'] 在 Windows 上: console.log(process.env.PATH); // 打印: 'C:\Windows\system32;C:\Windows;C:\Program Files\node\' process.env.PATH.split(path.delimiter); // 返回: ['C:\\Windows\\system32', 'C:\\Windows', 'C:\\Program Files\\node\\'] ------------------------------------------------------------------------------ console.log(path.sep);//環境變量分隔符(windows中使用; linux中使用:) 在 POSIX 上: 'foo/bar/baz'.split(path.sep); // 返回: ['foo', 'bar', 'baz'] 在 Windows 上: 'foo\\bar\\baz'.split(path.sep); // 返回: ['foo', 'bar', 'baz'] 在 Windows 上,正斜槓(/)和反斜槓(\)都被接受爲路徑片斷分隔符。 可是, path 方法只添加反斜槓(\)。
/* 異步I/O input/output 一、文件操做 二、網絡操做 在瀏覽器中也存在異步操做: 一、定時任務 二、事件處理 三、Ajax回調處理 js的運行時單線程的 引入事件隊列機制 Node.js中的事件模型與瀏覽器中的事件模型相似 單線程+事件隊列 Node.js中異步執行的任務: 一、文件I/O 二、網絡I/O 基於回調函數的編碼風格 */
Stats { dev: 2114,//該文件的設備的數字標識符 ino: 48064969,//文件系統特定的文件索引節點編號 mode: 33188,//描述文件類型和模式的位字段 nlink: 1,//文件存在的硬連接數 uid: 85,//擁有該文件(POSIX)的用戶的數字型用戶標識符 gid: 100,//擁有該文件(POSIX)的羣組的數字型羣組標識符 rdev: 0,//若是文件被視爲特殊文件,則此值爲數字型設備標識符 size: 527,//文件的大小(以字節爲單位) blksize: 4096,//用於 I/O 操做的文件系統塊的大小 blocks: 8,//爲此文件分配的塊數 atimeMs: 1318289051000.1,//代表上次訪問此文件的時間戳,以 POSIX 紀元以來的毫秒數表示 mtimeMs: 1318289051000.1,//代表上次修改此文件的時間戳,以 POSIX 紀元以來的毫秒數表示 ctimeMs: 1318289051000.1,//代表上次更改文件狀態的時間戳,以 POSIX 紀元以來的毫秒數表示 birthtimeMs: 1318289051000.1,//代表此文件的建立時間的時間戳,以 POSIX 紀元以來的毫秒數表示 atime: Mon, 10 Oct 2011 23:24:11 GMT,//代表上次訪問此文件的時間戳 文件訪問時間 mtime: Mon, 10 Oct 2011 23:24:11 GMT,//代表上次修改此文件的時間戳 文件數據發生變化的時間 ctime: Mon, 10 Oct 2011 23:24:11 GMT,//代表上次更改文件狀態的時間戳 文件的狀態信息發生變化的時間(好比文件的權限) birthtime: Mon, 10 Oct 2011 23:24:11 GMT //表示此文件的建立時間的時間戳 文件建立的時間 }
經常使用判斷是否爲常規文件stats.isFile()和文件目錄stats.isDirectory()返回布爾值
fs.stat(path[, options], callback)
// const fs = require('fs'); // const pathsToCheck = ['./txtDir', './txtDir/file.txt']; //異步操做 // for (let i = 0; i < pathsToCheck.length; i++) { // fs.stat(pathsToCheck[i], function(err, stats) { // if(stats.isFile()){ // console.log(pathsToCheck[i]+'---文件'); // console.log(stats) // }else if(stats.isDirectory()){ // console.log(pathsToCheck[i]+'---目錄'); // console.log(stats) // }else{ // console.log(err) // } // }); // } // 同步操做Sync // console.log(1); // let ret = fs.statSync('./data.txt'); // console.log(ret); // console.log(2);
/* 讀文件操做 */ const fs = require('fs'); const path = require('path'); let strpath = path.join(__dirname,'data.txt'); fs.readFile(strpath,(err,data)=>{ if(err) return; console.log(data.toString()); }); 若是有第二個參數而且是編碼,那麼回調函數獲取到的數據就是字符串 若是沒有第二個參數,那麼獲得的就是Buffer實例對象 fs.readFile(strpath,'utf8',(err,data)=>{ if(err) return; // console.log(data.toString()); console.log(data); }); 同步操做 let ret = fs.readFileSync(strpath,'utf8'); console.log(ret);
/* 寫文件操做 */ const fs = require('fs'); const path = require('path'); // 異步操做 let strpath = path.join(__dirname,'data.txt'); fs.writeFile(strpath,'hello nihao','utf8',(err)=>{ if(!err){ console.log('文件寫入成功'); } }); let buf = Buffer.from('hi'); fs.writeFile(strpath,buf,'utf8',(err)=>{ if(!err){ console.log('文件寫入成功'); } }); // 同步操做 fs.writeFileSync(strpath,'tom and jerry');
將文件從一個地方寫入另外一個地方 const path = require('path'); const fs = require('fs'); let spath = path.join(__dirname,'../03-source','file.zip'); let dpath = path.join('C:\\Users\\www\\Desktop','file.zip'); let readStream = fs.createReadStream(spath); let writeStream = fs.createWriteStream(dpath); // 基於事件的處理方式 // $('input[type=button]').on('click',function(){ // console.log('hello'); // }); 方法一 // ----------------------------------- let num = 1; readStream.on('data',(chunk)=>{ num++; writeStream.write(chunk); }); readStream.on('end',()=>{ console.log('文件處理完成'+num); }); 方法二 // ----------------------------------- // pipe的做用直接把輸入流和輸出流 readStream.pipe(writeStream); 方法三 // ---------------------------------- fs.createReadStream(spath).pipe(fs.createWriteStream(dpath));
建立目錄fs.mkdir(path[, mode], callback)/fs.mkdirSync(path[, mode])
const path = require('path'); const fs = require('fs'); // 建立目錄 fs.mkdir(path.join(__dirname,'abc'),(err)=>{ console.log(err); }); fs.mkdirSync(path.join(__dirname,'hello')); // 建立 /tmp/a/apple 目錄,不管是否存在 /tmp 和 /tmp/a 目錄。 // recursive 屬性(指示是否應建立父文件夾)的對象 fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => { if (err) throw err; });
讀取目錄fs.readdir(path[, options], callback)/fs.readdirSync(path[, options])
const path = require('path'); const fs = require('fs'); // 讀取目錄 fs.readdir(__dirname,(err,files)=>{ files.forEach((item,index)=>{ fs.stat(path.join(__dirname,item),(err,stat)=>{ if(stat.isFile()){ console.log(item,'文件'); }else if(stat.isDirectory()){ console.log(item,'目錄'); } }); }); }); let files = fs.readdirSync(__dirname); files.forEach((item,index)=>{ fs.stat(path.join(__dirname,item),(err,stat)=>{ if(stat.isFile()){ console.log(item,'文件'); }else if(stat.isDirectory()){ console.log(item,'目錄'); } }); });
刪除目錄fs.rmdir(path, callback)/fs.rmdirSync(path)
// 刪除目錄 fs.rmdir(path.join(__dirname,'abc'),(err)=>{ console.log(err); }); fs.rmdirSync(path.join(__dirname,'qqq'));
/* 文件操做案例(初始化目錄結構) */ const path = require('path'); const fs = require('fs'); let root = 'C:\\Users\\www\\Desktop'; let fileContent = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div>welcome to this</div> </body> </html> `; // 初始化數據 let initData = { projectName : 'mydemo', data : [{ name : 'img', type : 'dir' },{ name : 'css', type : 'dir' },{ name : 'js', type : 'dir' },{ name : 'index.html', type : 'file' }] } // 建立項目跟路徑 fs.mkdir(path.join(root,initData.projectName),(err)=>{ if(err) return; // 建立子目錄和文件 initData.data.forEach((item)=>{ if(item.type == 'dir'){ // 建立子目錄 fs.mkdirSync(path.join(root,initData.projectName,item.name)); }else if(item.type == 'file'){ // 建立文件並寫入內容 fs.writeFileSync(path.join(root,initData.projectName,item.name),fileContent); } }); });
傳統的動態網站開發須要應用軟件 PHP : Apache + php模塊 java :Tomcat 、Weblogic Node.js : 不須要應用軟件(能夠本身實現) /* Node.js的Web開發相關的內容: 一、Node.js不須要依賴第三方應用軟件(Apache),能夠基於api本身實現 二、實現靜態資源服務器 三、路由處理 四、動態網站 五、模板引擎 六、get和post參數傳遞和處理 Web開發框架:express */
const http = require('http'); // // 建立服務器實例對象 let server = http.createServer(); console.log(server) Server { _events: [Object: null prototype] { connection: [Function: connectionListener] }, _eventsCount: 1, _maxListeners: undefined, _connections: 0, _handle: null, _usingWorkers: false, _workers: [], _unref: false, allowHalfOpen: true, pauseOnConnect: false, httpAllowHalfOpen: false, timeout: 120000,//超時時間(以毫秒爲單位)。默認值: 120000(2 分鐘) keepAliveTimeout: 5000,//超時時間(以毫秒爲單位)。默認值: 5000(5 秒)更改此值僅影響到服務器的新鏈接,而不影響任何現有鏈接 maxHeadersCount: null,//限制最大傳入請求頭數。 若是設置爲 0,則不會應用任何限制 默認值: 2000 headersTimeout: 40000,//限制解析器等待接收完整 HTTP 請求頭的時間 默認值: 40000 [Symbol(IncomingMessage)]: { [Function: IncomingMessage] super_: { [Function: Readable] ReadableState: [Function: ReadableState], super_: [Function], _fromList: [Function: fromList] } }, [Symbol(ServerResponse)]: { [Function: ServerResponse] super_: { [Function: OutgoingMessage] super_: [Function] } }, [Symbol(asyncId)]: -1 }
http.createServer
方法會返回一個http.Server
對象實例,requestListener
可選參數傳入時,將作爲http.Server
對象'request'
事件的監聽器。
request
<http.IncomingMessage>response
<http.ServerResponse>每次有請求時都會觸發。 每一個鏈接可能有多個請求(在 HTTP Keep-Alive 鏈接的狀況下)。
/* 初步實現服務器功能 */ const http = require('http'); // ----------------------------- 方法一: // 建立服務器實例對象 let server = http.createServer(); console.log(server) // 綁定請求事件 server.on('request',(req,res)=>{ res.end('hello'); }); // 監聽端口 server.listen(3000); // ----------------------------- 方法二: http.createServer((req,res)=>{ res.end('ok');//response.end([data[, encoding]][, callback]) }).listen(3000,'192.168.0.106',()=>{ console.log('running...'); });
res.end()就是上述response類的方法;[response.end(data[, encoding]][, callback])
res.end('ok','utf-8',()=>{ console.log('一切正常') });
此方法與 net.Server
中的 server.listen()
相同。
上一例子也可,詳細可見官方api server.listen({ host: 'localhost', port: 80, exclusive: true });
一、req對象是Class: http.IncomingMessage的實例對象
二、res對象是Class: http.ServerResponse的實例對象
const http = require('http'); http.createServer((req,res)=>{ // req.url能夠獲取URL中的路徑(端口以後部分) // res.end(req.url); if(req.url.startsWith('/index')){ // write向客戶端響應內容,能夠寫屢次 res.write('hello'); res.write('hi'); res.write('nihao'); // end方法用來完成響應,只能執行一次 res.end(); }else if(req.url.startsWith('/about')){ res.end('about'); }else{ res.end('no content'); } }).listen(3000,'192.168.0.106',()=>{ console.log('running...'); });
res.write()就是上述response類的方法;[response.write(chunk, encoding][, callback])
/* 響應完整的頁面信息 */ const http = require('http'); const path = require('path'); const fs = require('fs'); // 根據路徑讀取文件的內容,而且響應到瀏覽器端 let readFile = (url,res) => { fs.readFile(path.join(__dirname,'www',url),'utf8',(err,fileContent)=>{ if(err){ res.end('server error'); }else{ res.end(fileContent); } }); } http.createServer((req,res)=>{ // 處理路徑的分發 if(req.url.startsWith('/index')){ readFile('index.html',res); }else if(req.url.startsWith('/about')){ readFile('about.html',res); }else if(req.url.startsWith('/list')){ readFile('list.html',res); }else{ // 設置相應類型和編碼 res.writeHead(200,{ 'Content-Type':'text/plain; charset=utf8' }); res.end('頁面被狗狗叼走了'); } }).listen(3000,'192.168.0.106',()=>{ console.log('running...'); });
設置響應頭[response.writeHead(statusCode, statusMessage][, headers])與response.setHeader(name, value)
當使用 response.setHeader()
設置響應頭時,它們將與傳給 response.writeHead()
的任何響應頭合併,其中 response.writeHead()
的響應頭優先。
// 返回 content-type = text/plain const server = http.createServer((req, res) => { res.setHeader('Content-Type', 'text/html'); res.setHeader('X-Foo', 'bar'); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('ok'); });
const url = require('url'); console.log(url) { Url: [Function: Url], parse: [Function: urlParse], resolve: [Function: urlResolve], resolveObject: [Function: urlResolveObject], format: [Function: urlFormat], URL: [Function: URL], URLSearchParams: [Function: URLSearchParams], domainToASCII: [Function: domainToASCII], domainToUnicode: [Function: domainToUnicode], pathToFileURL: [Function: pathToFileURL], fileURLToPath: [Function: fileURLToPath] }
parse方法的做用就是把URL字符串轉化爲對象
const url = require('url'); let str = 'http://www.baidu.com/abc/qqq?flag=123&keyword=java'; let ret = url.parse(str) console.log(ret) //如下能夠參展urlObject Url { protocol: 'http:',//協議 slashes: true,// url裏characters (/)的是true,不然false auth: null,//用戶名和密碼 host: 'www.baidu.com',//主機地址 主機名+端口 port: null,//端口 hostname: 'www.baidu.com',//主機名 hash: null,//characters (#) search: '?flag=123&keyword=java',//查詢參數 query: 'flag=123&keyword=java',//去掉?的查詢參數 pathname: '/abc/qqq',//路徑名 path: '/abc/qqq?flag=123&keyword=java',//路徑 href: 'http://www.baidu.com/abc/qqq?flag=123&keyword=java' //完整url }
第二個參數parseQueryString
其實將query.parse了
const url = require('url'); let str = 'http://www.baidu.com/abc/qqq?flag=123&keyword=java'; let ret = url.parse(str,true) console.log(ret) Url { protocol: 'http:', slashes: true, auth: null, host: 'www.baidu.com', port: null, hostname: 'www.baidu.com', hash: null, search: '?flag=123&keyword=java', query: [Object: null prototype] { flag: '123', keyword: 'java' }, pathname: '/abc/qqq', path: '/abc/qqq?flag=123&keyword=java', href: 'http://www.baidu.com/abc/qqq?flag=123&keyword=java' }
format的做用就是把對象轉化爲標準的URL字符串
url.format({ protocol: 'https', hostname: 'example.com', pathname: '/some/path', query: { page: 1, format: 'json' } }); // => 'https://example.com/some/path?page=1&format=json'
querystring
模塊提供用於解析和格式化 URL 查詢字符串的實用工具。 它可使用如下方式訪問:
const querystring = require('querystring');
parse方法的做用就是把字符串轉成對象
str
string 要解析的 URL 查詢字符串。sep
string 用於在查詢字符串中分隔鍵值對的子字符串。默認值: '&'
。eq
string 用於在查詢字符串中分隔鍵和值的子字符串。默認值: '='
。options
object
querystring.parse()
方法將 URL 查詢字符串 str
解析爲鍵值對的集合。
例如,查詢字符串 'foo=bar&abc=xyz&abc=123'
被解析爲:
const querystring = require('querystring'); let param = 'foo=bar&abc=xyz&abc=123'; let obj = querystring.parse(param); console.log(obj); { foo: 'bar', abc: ['xyz', '123'] }
querystring.parse()
方法返回的對象不是原型繼承自 JavaScript Object
。 這意味着典型的 Object
方法如 obj.toString()
、 obj.hasOwnProperty()
等都沒有定義而且不起做用。
stringify的做用就是把對象轉成字符串
obj
object 要序列化爲 URL 查詢字符串的對象。sep
string 用於在查詢字符串中分隔鍵值對的子字符串。默認值: '&'
。eq
string 用於在查詢字符串中分隔鍵和值的子字符串。默認值: '='
。options
encodeURIComponent
function 在查詢字符串中將 URL 不安全字符轉換爲百分比編碼時使用的函數。默認值: querystring.escape()
。querystring.stringify()
方法經過迭代對象的自身屬性從給定的 obj
生成 URL 查詢字符串。
它序列化了傳入 obj
中的如下類型的值: | | | <string[]> | <number[]> | <boolean[]>。 任何其餘輸入值都將被強制轉換爲空字符串。
querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' }); // 返回 'foo=bar&baz=qux&baz=quux&corge=' querystring.stringify({ foo: 'bar', baz: 'qux' }, ';', ':'); // 返回 'foo:bar;baz:qux' let obj1 = { flag : '123', abc : ['hello','hi'] } let str1 = querystring.stringify(obj1); console.log(str1);
const querystring = require('querystring'); const http = require('http'); http.createServer((req,res)=>{ if(req.url.startsWith('/login')){ let pdata = ''; req.on('data',(chunk)=>{ // 每次獲取一部分數據 pdata += chunk; }); req.on('end',()=>{ // 這裏才能獲得完整的數據 console.log(pdata); let obj = querystring.parse(pdata); res.end(obj.username+'-----'+obj.password); }); } }).listen(3000,()=>{ console.log('running...'); }) //這裏能夠本身用postman調試