使用noode.js创建一个服务器
一、簡單的靜態(tài)服務(wù)器
1、代碼解析
var http = require('http') // http是nodejs里面的一個模塊,這個對象能夠提供實現(xiàn)底層的方法。我們通過require去加載這個模塊var server = http.createServer(function(req, res){// 函數(shù)內(nèi)部創(chuàng)建一個服務(wù)器,創(chuàng)建好之后,通過瀏覽器訪問這個服務(wù)器的時候,會把請求封裝成一個對象// 這個對象就是這個回調(diào)函數(shù)的第一個參數(shù)req。用戶請求的信息都在這個對象內(nèi),可以獲取用戶的信息,如ip,請求信息等。// 第二個參數(shù)res是服務(wù)器返回給用戶的信息console.log('jiengu')res.setHeader("Content-Type","text/html; charset=utf-8")//設(shè)置響應(yīng)頭的content-type內(nèi)容,text/html是把響應(yīng)體當(dāng)成html解析,res.write('<h1> 饑人谷</h1>')//在res寫入服務(wù)器返回給瀏覽器的內(nèi)容res.end() }) server.listen(9000) // 通過listen方法來啟動他,服務(wù)器監(jiān)聽9000端口2、執(zhí)行步驟
打開gitbash,切換到j(luò)s文件當(dāng)前的文件夾,然后輸入node index.js(index.js是我的js文件名,反正你們?nèi)∈裁疵洼斎肷睹?#xff09;
打開瀏覽器,輸入http://127.0.0.1:9000/,或者h(yuǎn)ttp://localhost:9000/
注意哈9000是代碼里面寫的9000端口,如果下次改成了8080等其他的端口,那就改成對應(yīng)的端口就好
3、響應(yīng)頭和響應(yīng)體
響應(yīng)頭查看路徑:network-name-headers
響應(yīng)體:
響應(yīng)體是response的數(shù)據(jù),有點類似于打開網(wǎng)頁的查看源代碼
每次修改了js文件的內(nèi)容之后,要斷掉git的服務(wù)器,重新連接。不然即使刷新網(wǎng)頁沒有辦法顯示修改的內(nèi)容
4、設(shè)置響應(yīng)頭
4.1response.setHeader
格式:response.setHeader(name, value)
為一個隱式的響應(yīng)頭設(shè)置值。 如果該響應(yīng)頭已存在,則值會被覆蓋。 如果要發(fā)送多個名稱相同的響應(yīng)頭,則使用字符串?dāng)?shù)組。 非字符串的值會保留原樣,所以 response.getHeader() 會返回非字符串的值。 非字符串的值在網(wǎng)絡(luò)傳輸時會轉(zhuǎn)換為字符串。
舉例:
執(zhí)行結(jié)果
setHeader引申的鏈接,是nodejs中文網(wǎng)的規(guī)范
4.2 response.writeHead()
writeHead文檔規(guī)范
格式:response.writeHead(statusCode, statusMessage)
參數(shù)1 statusCode(狀態(tài)碼)是一個三位數(shù)的 HTTP 狀態(tài)碼,如 404。
參數(shù)2是 statusMessage 是可選的狀態(tài)描述,是一個string。
參數(shù)3 headers 是響應(yīng)頭,是個對象。其實我們可以理解為這個對象放的是response headers全部內(nèi)容。我們設(shè)置的writehead的內(nèi)容處理status碼是放在general,其他的內(nèi)容都是封裝成一個對象放在響應(yīng)頭內(nèi)容response headers。
response.writeHead(404, 'Not Found') res.writeHead(200,'hhh', { 'Content-Type':'text/plain;charset=utf-8','X-Foo':'bar2222'});
4.3兩者的不同
- response.writeHead() 在消息中只能被調(diào)用一次,且必須在 response.end() 被調(diào)用之前調(diào)用。調(diào)用兩次就會報錯。 setheader可以多次調(diào)用
- headers.setheader()只允許您設(shè)置單一標(biāo)題。
writehead()允許您設(shè)置關(guān)于響應(yīng)頭的幾乎所有內(nèi)容,包括狀態(tài)代碼、內(nèi)容和多個標(biāo)題。
4.4遇到的坑
坑1:res.setHeader("Content-Type","text/html; charset=gbk")才是對的,charset=gbk必須放在Content-Type內(nèi)部,展示的時候也是在一起。(我猜想charset應(yīng)該是Content-Type的一部分)
如果分開寫成下面的格式,不會報錯,但charset就變成了響應(yīng)頭的單獨子項展示,而且charset=utf-8不會生效(下圖utf-8沒有生效就按照gbk去解碼,就出現(xiàn)了亂碼)。
res.setHeader('Content-Type', 'text/html'); res.setHeader("charset","utf-8")
所以一定注意寫法
坑2:writeHead只能寫一次,所有響應(yīng)頭要設(shè)置的內(nèi)容都要按照對象的格式,放在參數(shù)三headers里面。以下縮寫是正確的,要記住啊
res.writeHead(200,'hhh', { 'Content-Type':'text/plain;charset=utf-8','X-Foo':'bar2222'});坑3:response.setHeader() 設(shè)置的響應(yīng)頭會與 response.writeHead() 設(shè)置的響應(yīng)頭合并,但是如果設(shè)置的內(nèi)容重復(fù),以response.writeHead() 的優(yōu)先為準(zhǔn)。
var server = http.createServer(function(req, res){res.setHeader("Content-Type","text/html; charset=utf-8")res.setHeader('X-Foo', 'bar');res.writeHead(200,'hhh', { 'Content-Type':'text/plain;charset=utf-8','X-Foo':'bar2222'});res.write('<h1> 饑人谷2</h1>')res.end() }) server.listen(9000)執(zhí)行結(jié)果是:很明顯的看到setHeader和writeHead重復(fù)設(shè)置的內(nèi)容,都是以writeHead為準(zhǔn)的
4.5設(shè)置status的異常
res.writeHead(404,'hhh');當(dāng)我設(shè)置status為404,發(fā)現(xiàn)即使是請求成功回送之后,也會出現(xiàn)紅色。這是因為大家約定404就是一個錯誤的狀態(tài),所以status的值要按照約定來設(shè)置
二、一個可用的靜態(tài)服務(wù)器
搭建一個有圖片,css,js的資源的服務(wù)器,github代碼鏈接
1、步驟
輸出內(nèi)容
2、js代碼解析
var http = require('http') var path = require('path') // path模塊處理url,不同系統(tǒng)(mac/lincx/window)下對url的寫法可能不一致的。(一個寫成c:/project/code/a.png // 另外一個可能寫成/user/local/project/a.png)。path模塊會對這種情況自動處理url類型 var fs = require('fs') // fs模塊用來讀取文件數(shù)據(jù),也可以往文件里面寫數(shù)據(jù)。 var url = require('url') // url模塊可以自動解析url,得到一個對象,可以獲得對應(yīng)的信息。function staticRoot(staticPath, req, res){console.log(staticPath) //輸出static文件的絕對路徑,/user/documents/code/node-server/step1/staticconsole.log(req.url) //請求的url地址,第一次調(diào)用html時,為/index.html,第二次調(diào)用css時,就是css/a.cssvar pathObj = url.parse(req.url, true)// 解析url,得到url對象(包含protocal/hostname/port/pathname/query等等),即pathobj對象就是url的對象。本次要用的是pathnameconsole.log(pathObj)if(pathObj.pathname === '/'){pathObj.pathname += 'index.html'}//如果pathname沒有輸入(瀏覽器輸入的值只是localhost:8080,沒有后綴的話),服務(wù)器默認(rèn)選擇去讀取和發(fā)送index.html文件var filePath = path.join(staticPath, pathObj.pathname)// staticPath=static文件夾的絕對路徑, pathObj.pathname=調(diào)用文件的后綴地址。// 兩個加起來得到filePath(用戶輸入的url想要訪問文件的絕對路徑),舉例本文是/user/documents/code/node-server/step1/static/index.html// var fileContent = fs.readFileSync(filePath,'binary')// res.write(fileContent, 'binary')// // 采用同步的方式讀取filePath的文檔,把讀取的數(shù)據(jù)寫入res對象內(nèi)// res.end()fs.readFile(filePath, 'binary', function(err, fileContent){// 異步的方式來讀取filePath的文檔。binary指以二進(jìn)制的方式來讀取數(shù)據(jù),因為服務(wù)器不僅僅要讀取普通的數(shù)據(jù),需要兼容圖片和文件等數(shù)據(jù)。if(err){console.log('404')res.writeHead(404, 'not found')res.end('<h1>404 Not Found</h1>')// 在頁面展示404 Not Found。在res.end('數(shù)據(jù)')等于執(zhí)行res.write('數(shù)據(jù)')加上res.end()}else{console.log('ok')res.writeHead(200, 'OK')res.write(fileContent, 'binary')// 通過二進(jìn)制的方式發(fā)送數(shù)據(jù)res.end() }})}console.log(path.join(__dirname, 'static'))// 在瀏覽器輸入localhost:8080/index.html地址,瀏覽器向服務(wù)器發(fā)起請求。 // 服務(wù)器收到請求后,執(zhí)行相關(guān)函數(shù),解析req對象信息,得到了index.html的地址。 // 服務(wù)器根據(jù)解析的地址在本地static文件夾下找到對應(yīng)的index.html文件,讀取html里面數(shù)據(jù),并把數(shù)據(jù)放在res內(nèi),當(dāng)成字符串發(fā)給服務(wù)器。var server = http.createServer(function(req, res){staticRoot(path.join(__dirname, 'static'), req, res) //寫一個staticRoot函數(shù),來處理請求。/* 參數(shù)1:把哪個路徑當(dāng)成靜態(tài)文件路徑,傳遞路徑名。__dirname是nodejs里面的一個變量,代表當(dāng)前的server.js執(zhí)行的這個文件。path.join(__dirname, 'static')可以使用一個或多個字符串值參數(shù),該參數(shù)返回將這些字符串值參數(shù)結(jié)合而成的路徑。 var joinPath = path.join(__dirname, 'a', 'b', 'c'); console.log(joinPath); // D:\nodePro\fileTest\a\b\c, __dirname對應(yīng)的step1文件夾的路徑,加上static文件夾得路徑,就等于static的絕對路徑。、這樣的好處是每次絕對路徑發(fā)生變化的時候,不用重新去修改絕對路徑。*/ })server.listen(8080) //創(chuàng)建一個服務(wù)器,監(jiān)聽8080端口 console.log('visit http://localhost:8080' )3、代碼難點解析
3.1 path node.js文檔中的標(biāo)準(zhǔn)解釋
path 模塊用于處理文件與目錄的路徑。不同系統(tǒng)(mac/lincx/window)下對url的寫法可能不一致的。(一個寫成c:/project/code/a.png
// 另外一個可能寫成/user/local/project/a.png)。path模塊會對這種情況自動處理url類型
3.2 path.join([...paths])
參數(shù)...paths <string> :路徑片段的序列,返回: <string>
使用平臺特定的分隔符把所有 path 片段連接到一起,并規(guī)范化生成的路徑
3.3 fs 文件系統(tǒng)node.js文檔中的標(biāo)準(zhǔn)解釋
fs 模塊用于以一種類似標(biāo)準(zhǔn) POSIX 函數(shù)的方式與文件系統(tǒng)進(jìn)行交互。
所有的文件系統(tǒng)操作都有同步和異步兩種形式。
異步形式的最后一個參數(shù)是完成時的回調(diào)函數(shù)。 傳給回調(diào)函數(shù)的參數(shù)取決于具體方法,但第一個參數(shù)會保留給異常。 如果操作成功完成,則第一個參數(shù)會是 null 或 undefined。
3.4 fs.readFile(path[, options], callback)異步地讀取文件的內(nèi)容
path 文件名或文件路徑
options 如果 options 是一個字符串,則指定字符編碼,默認(rèn)為 null
callback 是一個回調(diào)函數(shù),有兩個參數(shù) (err, data),其中 data 是要讀取文件的內(nèi)容
3.5 fs.readFileSync(path[, options])
同步的讀取文件內(nèi)容,兩個參數(shù)和異步的一樣的用法
3.6 url模塊node.js文檔中的標(biāo)準(zhǔn)解釋
url 模塊提供了一些實用函數(shù),用于 URL 處理與解析。 URL 字符串可以被解析為一個 URL 對象,其屬性對應(yīng)于字符串的各組成部分。
3.7url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
url.parse() 方法會解析一個 URL 字符串并返回一個 URL 對象。
urlString <string>
要解析的 URL 字符串。
parseQueryString <boolean>
如果為 true,則 query 屬性總會通過 querystring 模塊的 parse() 方法生成一個對象。 如果為 false,則返回的 URL 對象上的 query 屬性會是一個未解析、未解碼的字符串。 默認(rèn)為 false。
slashesDenoteHost <boolean>
如果為 true,則 // 之后至下一個 / 之前的字符串會被解析作為 host。 例如,//foo/bar 會被解析為 {host: 'foo', pathname: '/bar'} 而不是 {pathname: '//foo/bar'}。 默認(rèn)為 false。
舉個例子
3.8__dirname
當(dāng)前模塊的文件夾名稱。等同于 __filename 的 path.dirname() 的值
__filename 當(dāng)前模塊的文件名稱---解析后的絕對路徑
例如:
在 /Users/mjr 目錄下執(zhí)行 node example.js
4、坑
有一個問題,為什么我們要用req.url解析成url對象pathobj,再通過staticPath文件地址和pathobj.pastname結(jié)合成filepath,為啥我們不直接把req.url和staticPath結(jié)合在一起生成filepath呢?這樣還少了一步呢
答案:如果requrl是常規(guī)的index.html或者css.css這種,兩種方式都不會報錯。但是如果url比較復(fù)雜,像是index.html?query=111#111這種,直接把req.url和staticPath結(jié)合在一起是會報錯的,所以需要轉(zhuǎn)成url對象再把pashname挑出來。
三、實現(xiàn)一個簡單的node.js服務(wù)器路由
實現(xiàn)更復(fù)雜的服務(wù)器,url不僅僅是定位一個靜態(tài)文件,可以mock任何數(shù)據(jù)和前端交互。
1、核心原理:
根據(jù)瀏覽器請求的不同路由,導(dǎo)致服務(wù)器執(zhí)行不同的操作。
2、文檔結(jié)構(gòu):
3、服務(wù)器實現(xiàn)3條路由:
- /getWeather,結(jié)合b.js文件實現(xiàn)一個ajax來mock天氣數(shù)據(jù)
- /user/123 ,結(jié)合user.tpl文件實現(xiàn)用戶頁面
- /index.html,結(jié)合index.html實現(xiàn)index.html的頁面。在html引用css文件,b.js,和圖片
4、對應(yīng)的文件內(nèi)容
可以查看GitHub上面的代碼,我這里截圖說明
html
css
js,實現(xiàn)ajax的代碼
user.tpl
最重要的server-simple.js服務(wù)器代碼
本次演示的url是localhost:8080/user/123,localhost:8080之后的內(nèi)容是路由。所有請求到8080這個服務(wù)器內(nèi),根據(jù)不同的路由給瀏覽器發(fā)送不同的數(shù)據(jù)
5、執(zhí)行結(jié)果
index.html
/getWeather
/user/123
總結(jié)
以上是生活随笔為你收集整理的使用noode.js创建一个服务器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【修真院“善良”系列之十】初级Java程
- 下一篇: Vue根据条件添加click事件