node.js 學習筆記3 HTTP

path模塊

path模塊主要用于操作路徑。要使用path,首先需要引入path模塊。require('path')

path.resolve

用于拼接規范的絕對路徑。

如果想拼接一個路徑,有時候是使用字符串手動拼接的,但由于系統的規范不同,路徑中的\和/無法統一,有時候手動拼接的字符串路徑并不標準,path.resolve可以提供一種標準的絕對路徑。

path.resolve的參數是要拼接的路徑。path.resolve中,相對路徑可以省略./,但不能以/開頭,以/開頭的路徑會被識別為絕對路徑,作為根路徑與其他路徑參數進行拼接。

const path = require('path');let myPath = path.resolve(__dirname,'./demo.txt');

path.sep

獲取操作系統的路徑分隔符

windows的分隔符是\?

linux的分隔符是/

const tmp = path.sep;

path.parse

解析路徑并返回對象

__filename:和__dirname一樣是全局變量,里面保存的是文件所在文件夾的絕對路徑。

const path = require('path');const tmp = path.parse(__filename);
console.log(tmp);

root:文件盤符;dir:文件所在文件夾的路徑;base:文件名;ext:擴展名;name:文件名。

path.basename

獲取文件名,對應parse里的base。

path.dirname

獲取文件所在文件夾的路徑,即parse里的dir。

path.extname

獲取擴展名,即parse里的ext。

HTTP協議

HTTP:Hypertext Transfer Protocol超文本傳輸協議。

HTTP是互聯網應用最廣泛的協議之一。

協議:雙方必須遵守的一組約定。

HTTP協議:對瀏覽器和服務器之間的通信進行了約束。

請求:瀏覽器向服務器發起的通信。

響應:服務器給瀏覽器返回的結果。

請求報文:瀏覽器給服務器發送的數據。

響應報文:服務器給瀏覽器返回的數據。

請求報文和響應報文都是HTTP報文

當在瀏覽器中敲入URL,按回車時,瀏覽器就給對應的服務器發送了請求。

HTTP報文:

想要查看HTTP報文,可以借助工具,一個可以查看HTTP報文的工具是fiddler。fiddler的原理是,在安裝了fiddler之后,瀏覽器會把請求發給fiddler,fidder把請求轉發給服務器。服務器響應時,也把響應傳給fiddler,fiddler轉發給瀏覽器。

fiddler的下載:Download Fiddler Web Debugging Tool for Free by Telerik

官網填一下信息就能下載了。下載一路Next和agree就可以。

打開軟件后,點擊導航欄Tools下的options,勾選Decrypt HTTPS traffic按鈕,并在彈窗的時候選擇yes。然后重啟fiddler。

重新進入后,可以選擇只看瀏覽器請求,在左下角點擊All Processes,選擇Web Browsers。

如果想清空列表,可以點擊上面導航欄里的X,選擇Remove all。

想查看一個報文時,雙擊列表里的報文,就能在右側看到報文信息:

信息上面是請求報文Request,下面是響應報文Response。

原始請求/響應報文,可以點擊Raw查看。

按照提示點擊Response body is encoded.Click to decode,可以自動解碼,讓響應報文的信息不再是亂碼。

HTTP請求報文的結構:

以請求百度為例,點擊請求報文的raw,獲取如下信息:

GET https://www.baidu.com/ HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
sec-ch-ua: "Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Sec-Purpose: prefetch;prerender
Purpose: prefetch
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9
Cookie: BDUSS_BFESS=tJWE0tSExLdERyYzd-WnJYY29TY3E4NjBHbWkzUG9PWDY3TXNWbHNZeUVQS3htRVFBQUFBJCQAAAAAAAAAAAEAAAB5dRPqza~E6sPmsPx0b3BhegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAISvhGaEr4RmeG; PSTM=1733825412; BIDUPSID=04F444AAF0FB821D9DB875112E6F48D0; BD_UPN=12314753; MAWEBCUID=web_SEdQpQMWNWJYnmjuCByJwhagZSZOaTHKPCtmgSwfuNPUFTOFxs; BAIDUID=BE4A6D99C0702A98AA324A96A68ED83E:SL=0:NR=10:FG=1; H_WISE_SIDS_BFESS=62325_62969_63144_63195_63210_63243_63253_63357_63378_63383_63186_63394_63393_63390_63404; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; delPer=0; BD_CK_SAM=1; PSINO=2; BAIDUID_BFESS=BE4A6D99C0702A98AA324A96A68ED83E:SL=0:NR=10:FG=1; channel=baidusearch; baikeVisitId=f15c073a-0ffd-49e0-b898-40144ff8ef9c; BA_HECTOR=0gal21800k858k8k2ha50ha02gal271k9c5bl25; ZFY=L5NO43JVWWU3MBZjCkIsDKlDxVFGdwgXI2KmQMmDaeI:C; H_PS_PSSID=62325_63144_63947_64011_64127_64173_64248_64245_64258_64260_64269_64308_64318_64326_64366_64362_64363_64403_64413_64427; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_WISE_SIDS=62325_63144_63947_64011_64127_64173_64248_64245_64258_64260_64269_64308_64318_64326_64366_64362_64363_64403_64413_64427; sug=3; sugstore=0; ORIGIN=0; bdime=0; H_PS_645EC=49earUefVsN%2ByYhzjL%2FWcXOSkQUH045XqWgq7TUmq1bdcgOP3TfA%2Bf%2FF7XUPvfcklN8e; Hm_lvt_aec699bb6442ba076c8981c6dc490771=1754359961,1754490996,1754610718,1754750394; Hm_lpvt_aec699bb6442ba076c8981c6dc490771=1754750394; HMACCOUNT=4DF589D7A7F85E98; BDSVRTM=0; COOKIE_SESSION=34_0_6_8_10_8_0_0_6_7_0_1_42_0_42_0_1754750434_0_1754750392%7C9%232283914_3_1754268230%7C2

HTTP報文由三部分組成:請求行,對應上面的Get https://www.baidu.com/ HTTP/1.1。請求行是報文的第一行內容。

第二行開始到空行處是請求頭,對應上面Host行到Cookie行。

剩下的內容是請求體,本次請求目前請求體是空的,所以空行后沒有內容。

請求頭和請求體之間有一行空行。

請求行:
GET https://www.baidu.com/ HTTP/1.1

請求行由三部分組成:請求方法(GET)、URL(https://www.baidu.com/)、HTTP版本號(HTTP/1.1)。

請求方法:

HTTP請求常見的請求方法有:GET(獲取數據)、POST(新增數據)、PUT/PATCH(更新數據)、DELETE(刪除數據)。

還有一些平常比較少用的方法:HEAD、OPTIONS、CONNECT、TRACE。

GET的應用場景:在地址欄中直接輸入URL訪問、點擊a鏈接、link標簽引入css、script標簽引入js、video與audio引入多媒體;img標簽引入圖片;form標簽中method為get、ajax的get請求。

POST的應用場景:form標簽中method為post;ajax的POST請求。

GET和POST的區別:

1.作用不同,GET主要用來獲取數據,POST主要用來提交數據(但這不是絕對的,也可以通過POST獲取數據,通過GET提交數據)。

2.參數的位置不同,GET的參數是將參數放在URL中,而POST請求的參數是在請求體中(但這也不是絕對的,GET請求也可以設置請求體,POST請求也可以在URL中傳參,只是一般不會這么用)。

3.安全性不同:POST相對GET來說安全一些,因為GET請求時,參數會暴露在地址欄中。

4.GET請求的大小有限制,一般為2K,而POST請求的大小沒有限制。

URL:

Uniform Resource Locator 統一資源定位符

URL是一個字符串,用于定位服務器中的資源。服務器中有很多資源,URL用于定位其中的某一個資源,服務器找到URL對應的資源后返回結果。

URL的組成:

以下面的路徑為例:

https://mp.csdn.net:80/mp_blog/creation/editor?spm=1001.2014.3001.4503

https://mp.csdn.net:80/mp_blog/creation/editor?spm=1001.2014.3001.4503

協議名:https

主機名:mp.csdn.net

端口號:80

路徑:/mp_blog/creation/editor

查詢字符串:?spm=1001.2014.3001.4503

URL中,端口號之后,?之前的部分是路徑,路徑用于定位服務器中的某一個資源。

查詢字符串是?及后面的部分,格式是key1=value1&key2=value2&key3=value3……,查詢字符串用于向服務器傳遞參數,是對請求資源額外的一種描述。

URL有絕對路徑和相對路徑兩種形式。

絕對路徑:絕對路徑有三種形式,一種是整個完整的路徑;一種是省略協議的URL(省略協議時,會把當前頁面的協議和URL拼接形成完整的URL);一種是省略URL、IP地址、端口號的URL,以\開頭(省略URL、IP地址、端口號時,會把當前頁面的URL、IP地址、端口號和以\開頭的URL進行拼接,形成完整的URL)。

在使用省略URL、IP、端口號的絕對路徑時,可以避免當前請求服務器主機名改變時,需要修改URL的問題。

相對路徑:

相對路徑也有多種形式,以./開頭的路徑;直接就是文件路徑沒有./;../開頭的路徑。

使用相對路徑時,需要與當前URL頁面路徑進行計算,得到完整的URL之后,再發送請求。

比如當前的目錄是http://www.text.com/login/myLogin,如果請求的URL是../img/login.png,最終的請求路徑是http://www.text.com/login/img/login.png。

如果請求URL是text.css,或./text.css最終的請求路徑是http://www.text.com/login/myLogin/text.css。

相對路徑是不可靠的,在實際開發中,很少使用相對路徑。

URL使用場景:a href、link href、script src、img src、video src、audio src、form action、ajax url等,在這些地方,URL可以是相對路徑,也可以是絕對路徑。

HTTP版本號:

HTTP版本:1.0(1996年發布)、1.1(1999年發布)、2(2015年發布)、3(2018年發布)

請求頭:

請求頭是以一系列的key(鍵名):value(鍵值)對組成。

請求頭中可以記錄瀏覽器相關的一些信息:

User-Agent:記錄了瀏覽器的平臺、版本號等。

Accept:記錄了瀏覽器能夠處理的數據類型。

Accept-Encoding:記錄了瀏覽器支持的壓縮方式。

Accept-Language:記錄瀏覽器支持的語言。

Cookie:用于會話控制。

除了瀏覽器信息,請求頭中還有交互的行為信息:

Connection: Keep-alive。設置保持連接通道。

Upgrade-Insecure-Requests:1。設置升級HTTP請求為HTTPS,提高通信的安全性。

請求頭中還可以記錄和請求體相關的信息。

請求體:

請求體的內容格式非常靈活,可以設置任意內容。

請求體使用比較多的格式,是一個數組或者對象,且請求體是json格式。

HTTP響應報文:

HTTP/1.1 200 OK
Connection: keep-alive
Content-Security-Policy: frame-ancestors 'self' https://chat.baidu.com http://mirror-chat.baidu.com https://fj-chat.baidu.com https://hba-chat.baidu.com https://hbe-chat.baidu.com https://njjs-chat.baidu.com https://nj-chat.baidu.com https://hna-chat.baidu.com https://hnb-chat.baidu.com http://debug.baidu-int.com https://sai.baidu.com https://mcpstore.baidu.com https://mcpserver.baidu.com https://www.mcpworld.com https://platform-openai.now.baidu.com;
Content-Type: text/html; charset=utf-8
Date: Sat, 09 Aug 2025 14:50:32 GMT
Server: BWS/1.1
Set-Cookie: H_PS_PSSID=62325_63144_63947_64011_64127_64173_64248_64245_64258_64260_64269_64308_64318_64326_64366_64362_64363_64403_64413_64427; path=/; expires=Sun, 09-Aug-26 14:50:32 GMT; domain=.baidu.com
Traceid: 1754751032349825665010009797973434738610
X-Ua-Compatible: IE=Edge,chrome=1
X-Xss-Protection: 1;mode=block
Content-Length: 654507<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="origin-when-cross-origin" name="referrer"><meta name="theme-color" content="#ffffff"><meta name="description" content="全球領先的中文搜索引擎、致力于讓網民更便捷地獲取信息,找到所求。百度超過千億的中文網頁數據庫,可以瞬間找到相關的搜索結果。"><link rel="shortcut icon" href="https://www.baidu.com/favicon.ico" type="image/x-icon" /><link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" /><link rel="stylesheet" data-for="result" href="https://pss.bdstatic.com/r/www/static/font/cosmic/pc/cos-icon_3ff597f.css"/><link rel="icon" sizes="any" mask href="https://www.baidu.com/favicon.ico"><link rel="dns-prefetch" href="//dss0.bdstatic.com"/><link rel="dns-prefetch" href="//dss1.bdstatic.com"/><link rel="dns-prefetch" href="//ss1.bdstatic.com"/><link rel="dns-prefetch" href="//sp0.baidu.com"/><link rel="dns-prefetch" href="//sp1.baidu.com"/><link rel="dns-prefetch" href="//sp2.baidu.com"/><link rel="dns-prefetch" href="//pss.bdstatic.com"/><link rel="apple-touch-icon-precomposed" href="https://psstatic.cdn.bcebos.com/video/wiseindex/aa6eef91f8b5b1a33b454c401_1660835115000.png"><title>百度一下,你就知道</title><style index="newi" type="text/css">#form .bdsug{top:39px}.bdsug{display:none;position:absolute;width:535px;background:#fff;border:1px solid #ccc!important;_overflow:hidden;box-shadow:1px 1px 3px #ededed;-webkit-box-shadow:1px 1px 3px #ededed;-moz-box-shadow:1px 1px 3px #ededed;-o-box-shadow:1px 1px 3px #ededed}.bdsug li{width:519px;color:#000;font:14px arial;line-height:25px;padding:0 8px;position:relative;cursor:default}.bdsug li.bdsug-s{background:#f0f0f0}.bdsug-store span,.bdsug-store b{color:#7A77C8}.bdsug-store-del{font-size:12px;color:#666;text-decoration:underline;position:absolute;right:8px;top:0;cursor:pointer;display:none}.bdsug-s .bdsug-store-del{display:inline-block}.bdsug-ala{display:inline-block;border-bottom:1px solid #e6e6e6}.bdsug-ala h3{line-height:14px;background:url(//www.baidu.com/img/sug_bd.png?v=09816787.png) no-repeat left center;margin:6px 0 4px;font-size:12px;font-weight:400;color:#7B7B7B;padding-left:20px}.
.......
*** FIDDLER: RawDisplay truncated at 262144 characters. Right-click to disable truncation. ***

HTTP響應報文也由三部分組成:響應行、響應頭、響應體。

在響應頭和響應體之間有空行。

響應行:
HTTP/1.1 200 OK

由三部分組成:HTTP版本號(HTTP/1.1)、響應狀態碼(200)、響應狀態的描述(OK)

響應狀態碼:

是三位的數字,用來標識響應的結果狀態。

常見響應狀態碼:200(請求成功)、403(禁止請求)、404(找不到資源)、500(服務器內部錯誤)。

響應狀態碼的分類:1xx(信息響應)、2xx(成功響應)、3xx(重定向消息)、4xx(客戶端錯誤響應)、5xx(服務端錯誤響應)。

通過狀態碼,可以得知請求的結果。

響應狀態的描述:

響應狀態的描述是一個字符串,他與響應狀態碼是保持一一對應的。

200(OK)、403(Forbidden)、404(Not Found)、500(Internal Server Error)。

響應狀態碼的具體含義可以到MDN文檔上查詢。

響應頭:

記錄了與服務器相關的信息:

Server:記錄了服務器使用的技術。

Data:記錄了響應的時間。

記錄了與響應體相關的信息:

Content-Type:聲明響應體應用的格式與字符集。

Content-Length:記錄響應體的長度,單位是字節。

響應頭同樣可以到MDN上查詢。如果某個響應頭在MDN上無法搜到,這個響應頭是服務器自定義的,用于傳輸個性化數據。

響應體:

響應體與請求體類似,格式十分靈活,可以傳遞各種信息。

常見的響應體有:HTML、CSS、JavaScript、圖片、視頻、JSON等。

IP

IP類似于快遞的收件地址,在網絡世界中,IP地址用于尋找網絡設備。

IP也叫IP地址,是一個數字標識。

IP是32位的二進制數字,IP的表示方式,是把每8位(一字節)分為一組,再把8位二進制轉換為十進制數字,各組之間用點分隔。

IP地址的作用:標識網絡中的設備,實現設備間的通信。

每一個接入網絡的設備,手表、音響、電視、主機等,都有自己的IP地址。有了IP地址,通信雙方就可以通過IP找到對方。設備和設備之間才能通信。

IP共享技術:

32位二進制數據最多能表示2的32次方的IP地址,即42(億)94967296個。

但這個數字遠遠小于世界人口,如果人手一個設備,IP地址是不夠的,尤其是現在社會下,很多人往往擁有多個設備。

在32位IP不夠用的情況下,提出了一些共享IP的技術。

區域共享:在一個區域下的設備,所有設備共享一些IP。

家庭共享:家庭里的設備,所有設備共用一個IP。

比如在家庭里,所有的設備(手機、電腦、打印機、顯示器)都連接(通過WIFI或者物理線路)到路由器,路由器給每個設備都分配一個IP地址,而路由器本身也有一個IP地址,就形成了一個局域網。路由器分配的IP地址叫局域網IP,也叫私網IP。在局域網中,設備之間可以互相通信。如果想和其他網絡通信,路由器就需要接入互聯網。通過到通信公司(連通、移動)等辦理業務,可以接入互聯網。會從外部拉一根線到路由器上,接到這根線之后,路由器會有另一個IP,這個IP被稱為廣域網IP(或叫公網IP),有了公網IP,就可以和外部的網絡通信。

每一個家庭都可以按照同樣的方式分配IP,每個家庭內部都可以按同樣的IP分配IP地址,進行IP的復用(實現局域網復用)。再通過不同的公網IP,就可以實現相互的通信。

本地回環IP地址:

這個IP一直指向當前的設備本身。

IP分類:

本機回環IP地址:127.0.0.1~127.255.255.254

局域網IP(私網IP):192.168.0.0~192.168.255.255、172.16.0.0~172.31.255.255、10.0.0.0~10.255.255.255

廣域網IP(公網IP):除本機回環IP地址和局域網IP的IP

以上分類只是一個籠統的分類,如果想了解IP的分類細節,需要去學習IP標準分類。

端口

端口是應用程序的數字標識。

一臺計算機有65536個端口,端口號的范圍是0~65535。

一個應用程序可以使用一個或多個端口。

端口的作用:實現不同主機應用程序之間的通信。也就是說,當需要與一臺計算機通信時,通過IP可以找到這臺計算機,但是數據具體應該傳輸給哪個程序,是通過端口確定的。

HTTP模塊

通過node.js創建一個HTTP服務:有了HTTP服務,就可以處理瀏覽器發送過來的HTTP請求,并且給瀏覽器發送響應。

HTTP服務創建步驟:

1.導入HTTP模塊

const http = require('http')

2.創建服務對象

http.createServer() 用于創建服務對象,返回結果是一個對象。

http.createServer接收一個參數,該參數是一個函數,函數的參數是request(請求)、response(響應)。request是一個對象,是瀏覽器發來的請求報文的封裝對象。借助于這個對象,可以獲取請求報文的信息。response是對響應報文的封裝對象,可以用response給瀏覽器設置響應信息。該函數當服務器端接收到HTTP請求時執行。

const server = http.createServer((request,response)=>{

? ? ? ? response.end('Hello world')

})

response.end()用于設置響應體,并結束響應。

3.監聽端口,啟動服務

server.listen()。

參數是(端口號,回調函數),端口號是給當前服務器端設置的端口,回調函數在服務器端啟動成功時調用。

server.listen(5005,()=>{

? ? ? ? console.log('server start');

})

const http = require('http');const server = http.createServer((request,response)=>{response.end('hello world');}
)server.listen(5005, ()=>{console.log('server start!');
} )

當有人往服務器IP:5005發送請求時,這個請求會被交給當前開啟的服務器處理。在http.createServer中配置的參數函數(回調函數)會被執行。

用fiddler查看這個請求:

啟動服務之后如何停止服務:在命令行敲Ctrl+c

當服務器端的代碼有更新,需要保存代碼,重新啟動服務器之后,才能生效。

響應體中如果有中文,會出現亂碼

這是由于字符集設置有問題,可以通過response.setHeader設置響應頭,這個方法接收兩個參數,第一個參數是響應頭的名字,第二個參數是該key的value值。

在這里需要設置content-type為text/html;charset=utf-8。這個響應頭content-type可以告知瀏覽器響應體內容是text/html,字符集是utf-8。

const http = require('http');const server = http.createServer((request,response)=>{response.setHeader('content-type','text/html;charset=utf-8');response.end('你好世界');}
)server.listen(5005, ()=>{console.log('server start!');
} )

如果當前服務器設置的端口號已經被其他程序使用了,服務器無法正常啟動,啟動會報錯。可以把占用端口的程序停掉,空出這個端口解決問題。也可以更換當前服務器的端口為一個沒有程序使用的端口。

借助資源監視器,可以找到占用端口的程序。在開始里面搜索資源監視器并打開:

點擊網絡,在偵聽端口界面根據找到對應的程序,記住對應程序的PID:

打開任務管理器,找到對應的PID,把程序停掉:

HTTP協議的默認端口是80。在給服務器發送請求時,如果不添加端口號,則端口號是默認端口80。

HTTPS協議默認端口是443。

HTTP開發常用的端口:3000、8080、8090、9000等。

瀏覽器查看HTTP報文:

在瀏覽器中點擊F12,打開開發者窗口。點擊網絡(NetWork),可以查看網站使用過程中的所有報文信息。

favicon.ico:該請求是谷歌瀏覽器的默認行為,每次打開網頁時,都會發送這個請求去獲取網頁圖標。網頁圖標:網頁頁簽上的圖標。

點擊想查看的請求,右邊會出現請求報文和響應報文信息:

請求體內容可以在載荷(payload)中查看。GET請求沒有payload。

URL中的查詢字符串(?key1=value1&key2-value2&……)也可以在載荷里查看。

響應體在響應(Response)里查看。

在實際開發中,一般都是通過瀏覽器查看報文,不需要使用額外的工具。

提取HTTP請求報文:

本小節介紹如何在node.js服務器中提取報文信息。在瀏覽器把請求發送給后端時,后端服務器為了給瀏覽器返回正確的結果,就需要根據請求報文獲取相關信息。

在http.createServer回調函數的參數request中,獲取請求報文的相關信息。

request.method

可以獲取請求報文中,請求行的請求方法,也就是GET、POST等。

request.httpVersion

可以獲取請求報文中,請求行的HTTP協議版本號。

request.headers

可以獲取請求報文的請求頭。

返回的結果是一個對象,對象中包含請求頭中的所有內容。

對象中,key的字母都是小寫字母。

如果只想獲取某個具體的請求頭,可以通過request.headers.key獲取。

提取URL:

request.url

可以獲取請求報文中,請求行的URL。

URL中只包含URL路徑和查詢字符串。

如果想獲取請求中的URL信息,雖然也可以使用request的url屬性獲取,但這種方式獲取的路徑有時候并不能滿足開發需求,可以使用Url模塊,更好地解析URL路徑。

url模塊

1.導入Url模塊

const url = require('url');

2.使用url模塊

url.parse(request.url); 用于提取request.url中的URL信息。

url.parse接收兩個參數,第一個參數是需要解析的URL,第二個參數是設置URL中的query屬性如何解析,如果是true,query屬性是一個對象。

const http = require('http');
const url = require('url');
const server = http.createServer((request,response)=>{console.log(url.parse(request.url));}
)server.listen(9000, ()=>{console.log('server start!');
} )

pathname:URL路徑。

query:查詢字符串。如果調用url.parse時,第二個參數不傳,或者為false,則返回的是字符串。如果是true,則返回對象。

設置url.parse第二個參數為true:

[Object:null prototype]只是一個提示,表示這個對象的原型指向null。

通過res.query.key,可以獲取query的value。

除了通過url模塊獲取URL,還可通過實例化URL對象獲取URL數據:

實例化URL對象

let url = new URL(URL地址)

URL地址可以有兩種形式:1.一個完整的URL地址;2.分成兩個參數,第一個參數是路徑和查詢字符串,第二個參數是協議、IP和端口號。

const http = require('http');const server = http.createServer((request,response)=>{const url = new URL('http://127.0.0.1:9000'+request.url);const url2 = new URL(request.url,'http://127.0.0.1:9000');console.log(url);console.log(url2);}
)server.listen(9000, ()=>{console.log('server start!');
} )

在URL中,serch和serchParams存儲著查詢字符串,search是字符串的形式,而searchParams是一種類對象的形式,如果想通過searchParams獲取key對應的value,語法是url.searchParams.get(key)。

獲取請求體

寫一個簡單的HTML,給服務器發送POST請求:

<body><form action="http://127.0.0.1:9000" method="post"><input type="text" name="name"><input type="password" name="pawd"><input type="submit" value="提交"></form>
</body>

1.給request綁定事件:

request.on('data',回調函數)

request請求體對象是一個可讀流對象,可以通過可讀流把request中的數據讀取。

let bodyData = '';

request.on('data',(chunk)=>{

? ? ? ? bodyData += chunk;

});

chunk本身是一個Buffer,但是當使用+操作時,chunk會自動轉換為字符串。

2.綁定end事件

end事件在可讀流讀完后會進行回調。可以在函數中設置響應等。

request.on('end',()=>{

? ? ? response.end('....');??

})

const http = require('http');const server = http.createServer((request,response)=>{let bodyData = '';request.on('data',(chunk)=>{bodyData += chunk;})request.on('end',()=>{response.end(bodyData);})}
)server.listen(9000, ()=>{console.log('server start!');
} )

根據URL路徑不同返回不同的結果:

在以上的例子中,不管請求路徑是什么,都默認返回http.createServer的回調函數。但在實際開發中,需要根據不同的請求路徑,返回不同的數據。

實際上,如果需要返回不同的內容,也可以都寫在createServer函數中。

如果需要通過method方法,以及請求地址判斷返回的內容,先通過request.method獲取方法,再通過request.url獲取請求路徑。然后再進行判斷,就能實現根據不同的路徑返回不同的結果。

由于網站會自動請求favicon.ico,所以最好在服務器端配置一下對favicon.ico的處理,否則瀏覽器發給服務器端請求,服務器端沒有處理的邏輯,請求也不會返回,會一直和服務器端建立聯系,占用資源。

完整代碼:

const http = require('http');const server = http.createServer((request,response)=>{let url = request.url;let method = request.method;console.log(method);console.log(url);if(method=='GET' && url=='/login'){response.end('login page');}else if(method=='GET' && url=='/register'){response.end('register page');}else{response.end('404 not found');}}
)server.listen(9000, ()=>{console.log('server start!');
} )

設置HTTP響應報文

本小節主要介紹response的屬性及方法。

通過response來設置響應結果。

response.statusCode

設置響應狀態碼,比如response.statusCode = 203;

statusCode默認是200。

response.statusMessage

設置響應狀態的描述,比如response.statusMessage = 'Not Found';

不過,一般情況下,響應狀態的描述和響應狀態碼都是一一對應的,不需要手動設置。

response.setHeader()

設置響應頭,第一個參數是響應頭的key,第二個參數是value。

response.setHeader('Server','Node.js');

key是大小寫都可以。

除了設置標準的響應頭,也可以設置自定義響應頭。

response.setHeader('demo','123');

setHeader也可以設置同名響應頭response.setHeader('demo',[1,2,3]);在這種情況下,會返回三個key都是demo的響應頭,value分別為1,2,3。

response.write()

設置響應體。

里面的參數就是響應體本身。在返回時,會把response.end和response.write的內容拼接在一起返回。

response.write可以多次調用。返回的響應體是多個write的拼接。

const http = require('http');const server = http.createServer((request,response)=>{response.write('123');response.write('456');response.write('123');response.end('89');}
)server.listen(9000, ()=>{console.log('server start!');
} )

response.end()

可以用于設置響應體。

在回調函數中,一次返回只能設置一個response.end。

在響應內容中,可以設置響應HTML代碼。

可以把以下HTML代碼放在end中返回:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><table><tr><td>1</td><td>2</td><td>3</td></tr><tr><td>4</td><td>5</td><td>6</td></tr><tr><td>7</td><td>8</td><td>9</td></tr></table><style>table,td,th{border: 1px solid black;}table,td{border-collapse: collapse;}td{padding: 10px 20px;}table tr:nth-child(odd){background-color: burlywood;}table tr:nth-child(even){background-color: blueviolet;}</style><script>let tds = document.querySelectorAll('td');tds.forEach(item=>{item.onclick = function(){this.style.background = 'blue';}})</script>
</body>
</html>
const http = require('http');const server = http.createServer((request, response) => {response.end(`<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><table><tr><td>1</td>...}})</script></body></html>`);}
)server.listen(9000, () => {console.log('server start!');
})

但通過這種方法返回HTML數據時,返回的HTML沒有代碼高亮和語法提示,在開發時十分不便,可以把HTML代碼寫在HTML文件中,然后在response.end()中,返回HTML文件。

思路是通過fs模塊讀取HTML文件,然后作為end的內容返回。

const http = require('http');
const fs = require('fs');const server = http.createServer((request, response) => {let html = fs.readFileSync(__dirname + '/demo.html');response.end(html);}
)server.listen(9000, () => {console.log('server start!');
})

通過這種方式返回HTML數據,一個是可以更好地編寫返回的HTML數據,一個是當修改HTML中的內容時,不需要重啟服務器也可以返回新的頁面,因為每次請求讀取的是HTML文件中的數據,而HTML文件中的數據已經更新了。

通過fs.readFileSync讀取的數據格式是Buffer,response.end也可以處理Buffer數據,因此不需要手動做類型轉換。

錯誤類型設置:

當請求發生錯誤時,如何返回準確的錯誤類型:

可以根據讀取文件回調函數的err判斷:

fs.readFile(filePath,(err,data)=>{

? ? ? ? if(err){

? ? ? ? ? ? ? ? response.setHeader('content-type','text/html;charset=utf-8');

? ? ? ? ? ? ? ? switch(err.code){

? ? ? ? ? ? ? ? ? ? ? ? case 'ENOENT':

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? response.statusCode = 404;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? response.end(404錯誤頁面對應的HTML文件);

? ? ? ? ? ? ? ? ? ? ? ? case 'EPERM':

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? response.statusCode = 403;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? response.end(403禁止訪問頁面對應的HTML文件);

? ? ? ? ? ? ? ? ? ? ? ? ...

? ? ? ? ? ? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? reponse.statusCode = 500;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? response.end(500對應頁面的HTML);

????????????????}

????????}

})

網頁資源加載的過程:

當通過瀏覽器訪問一個網頁時,網頁會向服務器端發送多次請求。

在輸入完URL之后,敲擊回車,首先瀏覽器會向服務器發送一個請求當前URL頁面的請求:

返回后,瀏覽器會對返回的HTML進行解析,當解析到外部的資源時,比如css資源等,瀏覽器會向服務器再次發送請求,請求CSS資源等。

當CSS的數據返回后,瀏覽器會對CSS進行解析,讓CSS中設置的樣式控制瀏覽器頁面的樣式。

當碰到圖片資源請求時,瀏覽器也會向服務器請求圖片資源,當服務器端返回圖片之后,瀏覽器會渲染并呈現圖片。

當碰到外部JS資源時,瀏覽器會向服務器端發起請求,請求JS資源。

也就是說,當瀏覽器請求數據時,并不是一次性就把數據全部請求到,而是在解析內容時,發現有資源需要向服務器請求時,多次發送請求。且多個請求之間并不是串行的,是并行的,也就是請求某個資源時,并不是一定要等前面的資源請求完畢才可以,如果資源之間沒有關聯,可以并行請求多個資源。

當一個HTML頁面中引用了外部CSS和JS,如何通過response.end返回:

如果一個HTML中通過link ref等方法引入了外部CSS,通過javascript src引入了外部JS,在response.end中,就不能直接返回HTML文件了。因為在這種情況下,即使是瀏覽器向服務器請求css或Js數據,服務器也會返回HTML文件。

如果想正確返回數據,應該調整createServer的邏輯:

當頁面請求css時,請求路徑會是一個css文件;請求js時,請求路徑會是一個js文件。通過請求URL,可以對響應數據進行判斷。

const http = require('http');
const fs = require('fs');const server = http.createServer((request, response) => {let html = fs.readFileSync(__dirname + '/demo.html');let { pathname } = request.url;if(pathname == '/'){response.end(html);}else if(pathname == './index.css'){response.end(__dirname + '/index.css');}else if(pathname == './index.js'){response.end(__dirname + '/index.js');}else{response.end('404 not found');}}
)server.listen(9000, () => {console.log('server start!');
})

但通過這種方法返回請求資源,需要編寫多個if else,這種寫法比較復雜。

靜態資源

靜態資源是指內容長時間不會改變的資源,圖片、視頻、CSS、JS、HTML、字體等一般都是靜態資源。

動態資源

動態資源是指內容經常發生更新的資源,比如搜索列表頁、首頁等,每次訪問返回的數據可能各不相同。

搭建靜態資源服務

靜態資源服務:用于給瀏覽器返回靜態資源。

在上面的例子中,通過if else判斷返回何種資源,是十分復雜和冗余的。

如果想完成下列響應:

GET /index.html 響應pages/index.html

GET /css/demo.css 響應pages/css/demo.css

GET /image/demo.jpg?響應pages/image/demo.jpg

一般URL的請求路徑,和文件路徑之間是有關聯的,所以可以通過通用關聯拼接文件路徑,而不需要每次都通過if else判斷。

拼接完路徑之后,通過fs讀取文件,再返回就可以了。

const http = require('http');
const fs = require('fs');const server = http.createServer((request, response) => {let { pathname } = request.url;let filePath = __dirname + '/page' + pathname;fs.readFile(filePath, (err,data)=>{if(err){response.statusCode = 500;response.end('fail');return ;}response.end(data);})
)server.listen(9000, () => {console.log('server start!');
})

靜態資源目錄:是指靜態資源存放的文件夾的目錄。靜態資源目錄,也叫網站根目錄。

在配置靜態資源服務時,就是拼接靜態資源目錄,再拼接靜態資源目錄和請求路徑,去這個路徑讀取文件。

...
let root = __dirname + '/page';
let filePath = root + pathname;
...

MIME類型

Multipurpose Internet Mail Extensions ,MIME。稱為媒體類型,或資源類型。

是一種標準,用來表示文檔、文檔、字節流的性質和格式。

MIME類型的結構:主類型/子類型。

text/html、text/css、image/jpeg、application/json。

在響應頭中,可以通過Content-Type來表明響應的MIME類型。瀏覽器會根據Content-Type類型來決定如何處理響應體資源。

常見的MIME類型對應:

html文件:text/html、css文件:text/css、JS文件:text/javascript、png圖片:image/png、jpg圖片:image/jpg、gif圖片:image/gif、MP3文件:audio/mpeg、MP4文件:video/mp4、json文件:application/json。

在服務端返回資源時,可以通過文件的后綴名決定返回的Content-Type類型:

1.通過path.extname(filePath).slice(1)獲取當前文件路徑的后綴。

2.聲明MIME類型對象mimes。

3.根據類型返回Context-Type值:response.setHeader('content-type',mimes[ext]);

對于未知的資源類型,可以設置Context-Type為application/octet-stream,瀏覽器碰到這種響應設置時,會對響應體的內容進行獨立存儲,也就是下載的效果。

當前,Content-Type的設置其實也可以不手動進行,因為瀏覽器有MIME嗅探功能,瀏覽器會根據響應體自動分析MIME類型,但是返回準確的MIME類型,是一種比較規范的開發模式。

為了防止中文亂碼問題,在設置Content-Type值時,一般需要再拼接一下';charset=uft-8'。

除了設置Content-Type,如果資源類型是HTML,在HTML中,通過<meta charset='UTF-8'>也可以給資源設置charset,也不會產生亂碼。

meta charset和Content-Type的優先級:Content-Type的優先級高于meta charset。

對于CSS、JS、圖片等資源,一般不需要給資源單獨設置字符集,他們的字符集一般是根據資源所在的網頁的字符集處理的。

所以一般判斷ext(文件后綴)是否是HTML,是HTML再設置charset。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95109.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95109.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95109.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Flutter Dialog、BottomSheet

屬性說明title標題content內容actions按鈕applicationName說明文字applicationVersion版本applicationLegalese版本基本使用class MyState extends State {AlertDialog delDialog(BuildContext context) {AlertDialog alertDialog AlertDialog(title: Text("提示"),…

《算法導論》第 19 章 - 斐波那契堆

引言斐波那契堆&#xff08;Fibonacci Heap&#xff09;是一種高效的可合并堆數據結構&#xff0c;由 Michael L. Fredman 和 Robert E. Tarjan 于 1984 年提出。它在許多優先隊列操作中提供了極佳的 amortized&#xff08;攤還&#xff09;時間復雜度&#xff0c;尤其適用于需…

MySQL-日志

MySQL-日志前言一、錯誤日志&#xff08;error log&#xff09;二、慢查詢日志(slow query log)三 、一般查詢日志(general log)四、 事務日志重做日志&#xff08;redo log&#xff09;回滾日志&#xff08;undo log&#xff09;五、 二進制日志(bin log)/歸檔日志 > 數據同…

嵌入式C語言編程:策略模式、狀態模式和狀態機的應用

概述 在沒有面向對象語法的C語言中&#xff0c;策略&#xff08;Strategy&#xff09;模式和狀態&#xff08;State&#xff09;模式都通過“上下文 接口”組合來模擬多態。 它們在代碼結構上幾乎一致&#xff0c;但設計意圖和應用場景卻差異很大。 本文分三部分深入剖析&…

人工智能、機器學習、深度學習:2025技術革命的深度解析

目錄 人工智能、機器學習、深度學習&#xff1a;技術革命的深度解析 引言 第一部分&#xff1a;人工智能的起源與演進 1.1 人工智能的定義 1.2 人工智能的歷史 1.3 人工智能的關鍵概念 a.知識表示&#xff08;Knowledge Representation&#xff09; b.搜索算法&#xf…

【Python】常用內置模塊

1.os 文件目錄 import os# 創建文件夾 os.mkdir(dir) # 判斷文件是否存在 os.path.exists(path) # 列出文件夾下文件列表 os.listdir(dir)""" 常用 """ # 當前文件相對路徑 os.getcwd()# 當前文件絕對路徑 os.path.abspath(__file__)# 當前文…

(Python)爬蟲進階(Python爬蟲教程)(CSS選擇器)

源代碼&#xff1a;#導入庫 import requests from bs4 import BeautifulSoup import pandas as pd#爬蟲函數 def scrape_books():#1.基本網址連接base_url "http://books.toscrape.com"#2.獲取基本網址responserequests.get(base_url)#3.檢查是否正常訪問if respons…

第七節 自然語言處理與Bert

自然語言處理與BERT模型&#xff1a;從基礎到實踐入門 自然語言處理&#xff08;NLP&#xff09;的核心目標之一是讓計算機理解人類語言的語義和上下文。本文將從基礎的字詞表示出發&#xff0c;逐步解析傳統模型的局限性、Self-attention的突破性思想&#xff0c;以及BERT如何…

攻擊者瞄準加密技術的基礎:智能合約

雖然利用許多智能合約中的安全漏洞已經成為網絡攻擊者的長期目標&#xff0c;但越來越多的安全公司開始關注使用欺詐性或混淆的智能合約從加密貨幣賬戶中竊取資金的騙局。 根據網絡安全公司 SentinelOne 本周發布的分析報告&#xff0c;在最近一次引人注目的攻擊中&#xff0c…

基于開源AI大模型、AI智能名片與S2B2C商城小程序的零售智能化升級路徑研究

摘要&#xff1a;在零售業數字化轉型浪潮中&#xff0c;人工智能技術正從“輔助工具”向“核心生產力”演進。本文聚焦開源AI大模型、AI智能名片與S2B2C商城小程序的協同應用&#xff0c;提出“數據感知-關系重構-生態協同”的三維創新框架。通過分析智能傳感、動態畫像與供應鏈…

機器學習 樸素貝葉斯

目錄 一.什么是樸素貝葉斯 1.1 從 “概率” 到 “分類” 二.樸素貝葉斯的數學基礎&#xff1a;貝葉斯定理 2.1 貝葉斯定理公式 2.2 從貝葉斯定理到樸素貝葉斯分類 2.3 “樸素” 的關鍵&#xff1a;特征獨立性假設 三、樸素貝葉斯的三種常見類型 3.1 高斯樸素貝葉斯&…

A Logical Calculus of the Ideas Immanent in Nervous Activity(神經網絡早期的M-P模型)

哈嘍&#xff0c;各位朋友大家上午好&#xff01;今天我們要一起啃下這篇神經科學與邏輯學交叉領域的奠基之作——McCulloch和Pitts的《A Logical Calculus of the Ideas Immanent in Nervous Activity》。這篇論文篇幅不長&#xff0c;但每一個定理、每一個假設都像精密齒輪&a…

大語言模型提示工程與應用:提示工程-提升模型準確性與減少偏見的方法

語言模型可靠性優化 學習目標 在本課程中&#xff0c;我們將學習通過提示工程提升模型事實準確性、減少偏見的有效方法。 相關知識點 語言模型可靠性優化 學習內容 1 語言模型可靠性優化 1.1 事實準確性增強 LLM可能生成看似合理但實際虛構的內容。優化策略包括&#x…

遇到前端導出 Excel 文件出現亂碼或文件損壞的問題

1. 檢查后端返回的數據格式確認接口響應&#xff1a;確保后端返回的是二進制流&#xff08;如 ArrayBuffer&#xff09;或 Base64 編碼的 Excel 文件&#xff0c;而非 JSON 字符串。用瀏覽器開發者工具&#xff08;Network 標簽&#xff09;檢查接口響應類型&#xff1a;正確的…

2025年Cloudflare WAF防護機制深度剖析:5秒盾繞過完全指南

2025年Cloudflare WAF防護機制深度剖析&#xff1a;5秒盾繞過完全指南 技術概述 Cloudflare作為全球領先的CDN和網絡安全服務提供商&#xff0c;其WAF&#xff08;Web Application Firewall&#xff09;防護系統已經成為現代Web安全的標桿。特別是其標志性的"5秒盾"…

【Android調用相冊、拍照、錄像】等功能的封裝

關于調用Android項目 關于Android中調用相機拍照、錄像&#xff0c;調用相冊選圖等是比較繁瑣的&#xff0c;為了減少代碼冗余&#xff0c;肯定需要封裝成工具類&#xff0c;最終使用大概如下&#xff0c;大部分代碼使用Java編寫&#xff0c;因為需要照顧到不適用kotlin的伸手…

Git 分支管理:從新開發分支遷移為主分支的完整指南

問題背景 我在使用 Git 進行開發時&#xff0c;由于原有的主分支遭到了污染&#xff0c;不得已在多方嘗試之后&#xff0c;決定替換原有的主分支。創建一個新分支并完成了重要修改&#xff1a; 基于提交 0fcb6df0f5e8caa3d853bb1f43f23cfe6d269b18 創建了 new-development 分支…

nginx常見問題(四):端口無權限

當 Nginx 日志報錯 bind() to 80 failed (13: Permission denied) 時&#xff0c;這通常是由于權限不足導致 Nginx 無法綁定到 80 端口&#xff08;該端口為系統特權端口&#xff09;。以下是詳細的問題分析與解決方案&#xff1a;一、問題原因分析80 端口屬于 系統特權端口&am…

【線性代數】線性方程組與矩陣——(3)線性方程組解的結構

上一節&#xff1a;【線性代數】線性方程組與矩陣——&#xff08;2&#xff09;矩陣與線性方程組的解 總目錄&#xff1a;【線性代數】目錄 文章目錄9. 向量組的線性相關性與線性方程組解的結構9.1. 向量組及其線性組合9.2. 向量組的線性相關性9.3. 向量組的秩9.4. 線性方程組…

機器學習-----K-means算法介紹

一、為什么需要 K-Means&#xff1f;在監督學習中&#xff0c;我們總把數據寫成 (x, y)&#xff0c;讓模型學習 x → y 的映射。 但現實中很多數據根本沒有標簽 y&#xff0c;例如&#xff1a;啤酒&#xff1a;熱量、鈉含量、酒精度、價格用戶&#xff1a;訪問時長、點擊次數、…