日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用noode.js创建一个服务器

發(fā)布時間:2025/4/5 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用noode.js创建一个服务器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、簡單的靜態(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)換為字符串。
舉例:

response.setHeader('Content-Type', 'text/plain'); //當(dāng)成字符串解析 response.setHeader('Content-Type','text/html; charset=utf-8')//當(dāng)成html解析,如果是css就設(shè)置為text/css

執(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、步驟

  • 我在step1文件夾下放置了server.js文件,static文件夾。static文件夾對應(yīng)放了css,png,js,html等文檔,并在html文檔內(nèi)引用了圖片,css,js資源。
  • 打開gitbash,切換step1文件夾,執(zhí)行node server.js
  • 打開瀏覽器輸入localhost:8080index.html,查看結(jié)果
  • 輸出內(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ī)范化生成的路徑

    path.join('C:\Users\jz\documents\code\node-server\step1' , 'static') //C:\Users\jz\documents\code\node-server\step1\static

    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)容

    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() }})

    3.5 fs.readFileSync(path[, options])
    同步的讀取文件內(nèi)容,兩個參數(shù)和異步的一樣的用法

    // var fileContent = fs.readFileSync(filePath,'binary')// res.write(fileContent, 'binary')// // 采用同步的方式讀取filePath的文檔,把讀取的數(shù)據(jù)寫入res對象內(nèi)// res.end()

    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。
    舉個例子

    var pathObj = url.parse(req.url, true)// 解析req.url,得到url對象pathobj


    3.8__dirname
    當(dāng)前模塊的文件夾名稱。等同于 __filename 的 path.dirname() 的值
    __filename 當(dāng)前模塊的文件名稱---解析后的絕對路徑
    例如:
    在 /Users/mjr 目錄下執(zhí)行 node example.js

    console.log(__filename); // Prints: /Users/mjr/example.js console.log(__dirname); // Prints: /Users/mjr

    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ù)

    var http = require('http') var fs = require('fs') var url = require('url')http.createServer(function(req, res){var pathObj = url.parse(req.url, true)console.log(pathObj)switch (pathObj.pathname){case '/getWeather': //根據(jù)req.url來執(zhí)行不同的函數(shù)var retif(pathObj.query.city == 'beijing'){ret = {city: 'beijing',weather: '晴天'}}else{ret = {city: pathObj.query.city,weather: '不知道'}}res.setHeader('content-Type','text/plain;charset=utf-8')res.end(JSON.stringify(ret)) //給瀏覽器輸入是一個json格式的對象,根據(jù)JSON.stringify轉(zhuǎn)換成字符串break;case '/user/123':res.end( fs.readFileSync(__dirname + '/static/user.tpl' ))//如果路由是/user/123,讀取user.tpl的內(nèi)容,并返回給瀏覽器break;default:res.end( fs.readFileSync(__dirname + '/static' + pathObj.pathname) )} }).listen(8080)

    5、執(zhí)行結(jié)果

    index.html

    /getWeather

    /user/123

    總結(jié)

    以上是生活随笔為你收集整理的使用noode.js创建一个服务器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。