概念
HTTP(hypertext transport protocol)協(xié)議;中文叫
超文本傳輸協(xié)議
是一種基于TCP/IP的應(yīng)用層通信協(xié)議
這個(gè)協(xié)議詳細(xì)規(guī)定了 瀏覽器 和 萬(wàn)維網(wǎng) 服務(wù)器 之間互相通信的規(guī)則
協(xié)議中主要規(guī)定了兩個(gè)方面的內(nèi)容:
- 客戶端:用來(lái)向服務(wù)器發(fā)送數(shù)據(jù),可以被稱之為
請(qǐng)求報(bào)文 - 服務(wù)端:向客戶端返回?cái)?shù)據(jù),可以被稱之為
響應(yīng)報(bào)文
報(bào)文:可以簡(jiǎn)單理解為就是一堆字符串
請(qǐng)求報(bào)文的組成
- 請(qǐng)求行
- 請(qǐng)求頭
- 空行
- 請(qǐng)求體
HTTP 的請(qǐng)求行

- 請(qǐng)求方式(get、post、put、delete等)
- 請(qǐng)求 URL(統(tǒng)一資源定位器)
- http: 協(xié)議 (https、ftp、ssh等)
- www.baidu.com 域名
- 80 端口號(hào)
- /index.html 路徑
- a=100&b=200 查詢字符串
- logo 哈希 (錨點(diǎn)鏈接)
- HTTP協(xié)議版本號(hào)
HTTP 請(qǐng)求頭
格式:『頭名:頭值』
常見(jiàn)的請(qǐng)求頭有:
| 請(qǐng)求頭 | 解釋 |
|---|---|
| Host | 主機(jī)名 |
| Connection | 連接的設(shè)置 keep-alive(保持連接);close(關(guān)閉連接) |
| Cache-Control | 緩存控制 max-age = 0 (沒(méi)有緩存) |
| Upgrade-Insecure-Requests | 將網(wǎng)頁(yè)中的http請(qǐng)求轉(zhuǎn)化為 https 請(qǐng)求(很少用)老網(wǎng)站升級(jí) |
| User-Agent | 用戶代理,客戶端字符串標(biāo)識(shí),服務(wù)器可以通過(guò)這個(gè)標(biāo)識(shí)來(lái)識(shí)別這個(gè)請(qǐng)求來(lái)自哪個(gè)客戶端 ,一般在PC端和手機(jī)端的區(qū)分 |
| Accept | 設(shè)置瀏覽器接收的數(shù)據(jù)類型 |
| Accept-Encoding | 設(shè)置接收的壓縮方式 |
| Accept-Language | 設(shè)置接收的語(yǔ)言 q=0.7 為喜好系數(shù),滿分為1 |
| Cookie | 后面單獨(dú)講 |
HTTP 的請(qǐng)求體
請(qǐng)求體內(nèi)容的格式是非常靈活的,
(可以是空)==> GET請(qǐng)求,
(也可以是字符串,還可以是JSON)===> POST請(qǐng)求
例如:
字符串:keywords=手機(jī)&price=2000
JSON:{"keywords":"手機(jī)","price":2000}
響應(yīng)報(bào)文的組成
-
響應(yīng)行:
HTTP/1.1 200 OKHTTP/1.1:HTTP協(xié)議版本號(hào)
-
200:響應(yīng)狀態(tài)碼 404 Not Found 500 Internal Server Error
還有一些狀態(tài)碼,參考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
OK:響應(yīng)狀態(tài)描述
響應(yīng)狀態(tài)碼 和 響應(yīng)字符串 關(guān)系是 一一對(duì)應(yīng) 的。
-
響應(yīng)頭
-
Cache-Control: 緩存控制 private 私有的,只允許客戶端緩存數(shù)據(jù) -
Connection: 鏈接設(shè)置 -
Content-Type:text/html;charset=utf-8: 設(shè)置響應(yīng)體的數(shù)據(jù)類型以及字符集,響應(yīng)體為html,字符集utf-8 -
Content-Length: 響應(yīng)體的長(zhǎng)度,單位為字節(jié)
-
空行
-
響應(yīng)體
響應(yīng)體內(nèi)容的類型是非常靈活的,常見(jiàn)的類型有 HTML、CSS、JS、圖片、JSON
創(chuàng)建 HTTP 服務(wù)
使用 nodejs 創(chuàng)建 HTTP 服務(wù)
操作步驟
//1. 導(dǎo)入 http 模塊
const http = require('http');
//2. 創(chuàng)建服務(wù)對(duì)象 create 創(chuàng)建 server 服務(wù)
// request 意為請(qǐng)求. 是對(duì)請(qǐng)求報(bào)文的封裝對(duì)象, 通過(guò) request 對(duì)象可以獲得請(qǐng)求報(bào)文的數(shù)據(jù)
// response 意為響應(yīng). 是對(duì)響應(yīng)報(bào)文的封裝對(duì)象, 通過(guò) response 對(duì)象可以設(shè)置響應(yīng)報(bào)文
const server = http.createServer((request, response) => {
// 設(shè)置響應(yīng)體
response.end('Hello HTTP server');
}); //=>返回結(jié)果是一個(gè)對(duì)象
//3. 監(jiān)聽(tīng)端口, 啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('服務(wù)已經(jīng)啟動(dòng), 端口 9000 監(jiān)聽(tīng)中...');
});
http.createServer里的回調(diào)函數(shù)的執(zhí)行時(shí)機(jī): <span style="color:red">當(dāng)接收到 HTTP 請(qǐng)求的時(shí)候,就會(huì)執(zhí)行</span>
測(cè)試
瀏覽器請(qǐng)求對(duì)應(yīng)端口
http://127.0.0.1:9000
注意事項(xiàng)
命令行
ctrl + c停止服務(wù)當(dāng)服務(wù)啟動(dòng)后,更新代碼必須重啟服務(wù)才能生效
-
響應(yīng)內(nèi)容中文亂碼的解決辦法
// 設(shè)置響應(yīng)頭 response.setHeader('content-type','text/html;charset=utf-8'); -
端口號(hào)被占用
Error: listen EADDRINUSE: address already in use :::90001)關(guān)閉當(dāng)前正在運(yùn)行監(jiān)聽(tīng)端口的服務(wù) ( 使用較多 )
2)修改其他端口號(hào)
HTTP協(xié)議默認(rèn)端口是80。HTTPS協(xié)議的默認(rèn)端口是443, HTTP 服務(wù)開(kāi)發(fā)常用端口有3000,8080,8090,9000等
如果端口被其他程序占用,可以使用資源監(jiān)視器找到占用端口的程序,然后使用任務(wù)管理器關(guān)閉對(duì)應(yīng)的程序
瀏覽器查看 HTTP 報(bào)文
點(diǎn)擊步驟

查看請(qǐng)求行與請(qǐng)求頭

查看請(qǐng)求體

查看 URL 查詢字符串

查看響應(yīng)行與響應(yīng)頭

查看響應(yīng)體

獲取 HTTP 請(qǐng)求報(bào)文
| 含義 | 語(yǔ)法 | 重點(diǎn)掌握 |
|---|---|---|
| 請(qǐng)求方法 | request.method |
***** |
| 請(qǐng)求版本 | request.httpVersion | |
| 請(qǐng)求路徑 | request.url |
***** |
| URL 路徑 | require('url').parse(request.url).pathname |
***** |
| URL 查詢字符串 | require('url').parse(request.url, true).query |
***** |
| 請(qǐng)求頭 | request.headers |
***** |
| 請(qǐng)求體 | request.on('data', function(chunk){}) request.on('end', function(){}) |
// 1. 導(dǎo)入 http 模塊
const http = require('http')
// 2. 創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// 獲取請(qǐng)求的方法
console.log(request.method) //=>GET
// 獲取請(qǐng)求的 url
console.log(request.url) // 只包含 url 中的 路徑 與查詢字符串
// 獲取 http 協(xié)議的版本號(hào)
console.log(request.httpVersion) //=> 1.1
// 獲取 http 的請(qǐng)求頭
console.log(request.headers) //=>結(jié)果是一個(gè)對(duì)象
response.end('http') //=>設(shè)置響應(yīng)體
})
// 3. 監(jiān)聽(tīng)端口,啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('服務(wù)已經(jīng)啟動(dòng)...')
})
注意事項(xiàng):
-
request.url只能獲取路徑以及查詢字符串,無(wú)法獲取 URL 中的域名以及協(xié)議的內(nèi)容 -
request.headers將請(qǐng)求信息轉(zhuǎn)化成一個(gè)對(duì)象,并將屬性名都轉(zhuǎn)化成了『小寫(xiě)』 - 關(guān)于路徑:如果訪問(wèn)網(wǎng)站的時(shí)候,只填寫(xiě)了 IP 地址或者是域名信息,此時(shí)請(qǐng)求的路徑為『
/』 - 關(guān)于
favicon.ico:這個(gè)請(qǐng)求是屬于瀏覽器自動(dòng)發(fā)送的請(qǐng)求
提取 http 報(bào)文的請(qǐng)求體
// 1. 導(dǎo)入 http 模塊
const http = require('http')
// 2. 創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// 1. 聲明一個(gè)變量
let body = ''
// 2. 綁定 data 事件
request.on('data', chunk => {
body += chunk
})
// 3. 綁定 end 事件
request.on('end', () => {
console.log(body) //=>'username=111&password=111'
// 響應(yīng)
response.end('Hello Http') //=>設(shè)置響應(yīng)體
})
})
// 3. 監(jiān)聽(tīng)端口,啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('服務(wù)已經(jīng)啟動(dòng)...')
})
提取 http 報(bào)文中 url的路徑 與 查詢字符串
// 導(dǎo)入 http 模塊
const http = require('http')
// 1. 導(dǎo)入 url 模塊
const url = require('url')
// 創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// 2. 解析 request.url
console.log(request.url) //=>/search?keyword=h5
// 使用 parse 解析 request.url 的內(nèi)容
// true 將 query 屬性將會(huì)設(shè)置為一個(gè) 對(duì)象
let res = url.parse(request.url, true)
console.log(res) // 如下圖所示,為一個(gè)對(duì)象
// 路徑
let pathname = res.pathname
// 查詢字符串
let keyword = res.query.keyword
console.log(keyword) //=>h5
response.end('url')
})
// 監(jiān)聽(tīng)端口,啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('服務(wù)已經(jīng)啟動(dòng)...')
})

// 導(dǎo)入 http 模塊
const http = require('http')
// 創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
// 實(shí)例化 url 對(duì)象
// let url = new URL('/search?a=100&b=200','http://127.0.0.1:9000')
let url = new URL(request.url, 'http://127.0.0.1')
console.log(url) //=>如圖所示,為一個(gè)對(duì)象
// 輸出路徑
console.log(url.pathname) //=>/search
// 輸出 keyword 查詢字符串
console.log(url.searchParams.get('a')) //=> 100
response.end('url new')
})
// 監(jiān)聽(tīng)端口,啟動(dòng)服務(wù)
server.listen(9000, () => {
console.log('服務(wù)已經(jīng)啟動(dòng)...')
})

練習(xí)
按照以下要求搭建 HTTP 服務(wù)
| 請(qǐng)求類型(方法) | 請(qǐng)求地址 | 響應(yīng)體結(jié)果 |
|---|---|---|
| get | /login | 登錄頁(yè)面 |
| get | /reg | 注冊(cè)頁(yè)面 |
//1、引入http模塊
const http = require("http");
//2、建立服務(wù)
const server = http.createServer((request,response)=>{
let {url, method} = request; //對(duì)象的解構(gòu)賦值
//設(shè)置響應(yīng)頭信息
//解決中文亂碼
response.setHeader("Content-Type","text/html;charset=utf-8")
if(url == "/register" && method == "GET"){
response.end("注冊(cè)頁(yè)面");
}else if(url=="/login" && method == "GET"){
response.end("登錄頁(yè)面");
}else{
response.end("<h1>404 Not Found</h1>")
}
})
//3、監(jiān)聽(tīng)端口
server.listen(8000,()=>{
console.log('服務(wù)啟動(dòng)中....');
})
設(shè)置 HTTP 響應(yīng)報(bào)文
| 作用 | 語(yǔ)法 |
|---|---|
| 設(shè)置響應(yīng)狀態(tài)碼 | response.statusCode |
| 設(shè)置響應(yīng)狀態(tài)描述 | response.statusMessage ( 用的非常少 ) |
| 設(shè)置響應(yīng)頭信息 | response.setHeader('頭名', '頭值') (可以自定義) |
| 設(shè)置響應(yīng)體 | response.write('xx') response.end('xxx')只能用1次 |
// 1. 設(shè)置響應(yīng)狀態(tài)碼
response.statusCode = 203
// 2. 響應(yīng)狀態(tài)的描述
response.statusMessage = 'i love you'
// 3. 響應(yīng)頭
response.setHeader('content-type', 'text/html;charset=utf-8')
// 自定義響應(yīng)頭
response.setHeader('myHeader', 'test test')
// 設(shè)置多個(gè)同名的響應(yīng)頭
response.setHeader('test', ['a', 'b', 'c'])
// write 和 end 的兩種使用情況:
// 1. write 和 end 的結(jié)合使用 響應(yīng)體相對(duì)分散
response.write('xx');
response.write('xx');
response.write('xx');
response.end(); //每一個(gè)請(qǐng)求,在處理的時(shí)候必須要執(zhí)行 end 方法的
//2. 單獨(dú)使用 end 方法 響應(yīng)體相對(duì)集中
response.end('xxx');
練習(xí)
搭建 HTTP 服務(wù),響應(yīng)一個(gè) 4 行 3 列的表格,并且要求表格有 隔行換色效果 ,且 點(diǎn)擊 單元格能 高亮顯示
方法一
// 導(dǎo)入 http 模塊
const http = require('http')
const fs = require('fs')
// 創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
response.setHeader('content-type', 'text/html;charset=utf-8')
response.end(` //這里為了能換行使用反引號(hào),英文狀態(tài)下1左邊的鍵
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
td {
padding: 20px 40px;
}
table tr:nth-child(odd) {
background-color: #aef;
}
table tr:nth-child(even) {
background-color: #fcb;
}
table,
td {
border-collapse: collapse;
}
</style>
</head>
<body>
<table border="1">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<script>
const tds = document.querySelectorAll('td')
tds.forEach(item => {
item.addEventListener('click', function () {
this.style.backgroundColor = '#000'
})
})
</script>
</body>
</html>
`)
})
// 監(jiān)聽(tīng)端口,啟動(dòng)服務(wù)器
server.listen(9000, () => {
console.log('服務(wù)器已經(jīng)啟動(dòng)...')
})
方法二
// 導(dǎo)入 http 模塊
const http = require('http')
const fs = require('fs')
// 創(chuàng)建服務(wù)對(duì)象
const server = http.createServer((request, response) => {
response.setHeader('content-type', 'text/html;charset=utf-8')
// 讀取文件內(nèi)容
let html = fs.readFileSync(__dirname + '/table.html')
// end 方法的參數(shù)可以是字符串也可以是Buffer
response.end(html)
})
// 監(jiān)聽(tīng)端口,啟動(dòng)服務(wù)器
server.listen(9000, () => {
console.log('服務(wù)器已經(jīng)啟動(dòng)...')
})
table.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
td {
padding: 20px 40px;
}
table tr:nth-child(odd) {
background-color: #aef;
}
table tr:nth-child(even) {
background-color: #fcb;
}
table,
td {
border-collapse: collapse;
}
</style>
</head>
<body>
<table border="1">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<script>
const tds = document.querySelectorAll('td')
tds.forEach(item => {
item.addEventListener('click', function () {
this.style.backgroundColor = '#000'
})
})
</script>
</body>
</html>
網(wǎng)頁(yè)資源的基本加載過(guò)程

網(wǎng)頁(yè)資源的加載都是循序漸進(jìn)的,首先獲取 HTML 的內(nèi)容, 然后解析 HTML 在發(fā)送其他資源的請(qǐng)求,如 CSS,Javascript,圖片等。>理解了這個(gè)內(nèi)容對(duì)于后續(xù)的學(xué)習(xí)與成長(zhǎng)有非常大的幫助
靜態(tài)資源服務(wù)
靜態(tài)資源 是指內(nèi)容長(zhǎng)時(shí)間不發(fā)生改變的資源 ,例如圖片,視頻,CSS 文件,JS文件,HTML文件,字體文件等
動(dòng)態(tài)資源 是指內(nèi)容經(jīng)常更新的資源 ,例如百度首頁(yè),網(wǎng)易首頁(yè),京東搜索列表頁(yè)面等
網(wǎng)站根目錄或靜態(tài)資源目錄
HTTP 服務(wù)在哪個(gè)文件夾中尋找靜態(tài)資源,那個(gè)文件夾就是靜態(tài)資源目錄 ,也稱之為網(wǎng)站根目錄
思考:vscode 中使用 live-server 訪問(wèn) HTML 時(shí), 它啟動(dòng)的服務(wù)中網(wǎng)站根目錄是誰(shuí)?
- 改文件的所處的文件夾
網(wǎng)頁(yè)中的 URL
網(wǎng)頁(yè)中的 URL 主要分為兩大類:相對(duì)路徑 與 絕對(duì)路徑
絕對(duì)路徑
絕對(duì)路徑可靠性強(qiáng),而且相對(duì)容易理解,在項(xiàng)目中運(yùn)用較多
| 形式 | 特點(diǎn) |
|---|---|
| http://atguigu.com/web | 直接向目標(biāo)資源發(fā)送請(qǐng)求,容易理解。網(wǎng)站的外鏈會(huì)用到此形式 |
| //atguigu.com/web | 與頁(yè)面 URL 的協(xié)議拼接形成完整 URL 再發(fā)送請(qǐng)求。大型網(wǎng)站用的比較多 |
| /web | 與頁(yè)面 URL 的協(xié)議、主機(jī)名、端口拼接形成完整 URL 再發(fā)送請(qǐng)求。中小型網(wǎng)站 |
相對(duì)路徑
相對(duì)路徑在發(fā)送請(qǐng)求時(shí),需要與當(dāng)前頁(yè)面 URL 路徑進(jìn)行 計(jì)算 ,得到完整 URL 后,再發(fā)送請(qǐng)求,學(xué)習(xí)階段用的較多
例如當(dāng)前網(wǎng)頁(yè) url 為 http://www.atguigu.com/course/h5.html
| 形式 | 最終的 URL |
|---|---|
| ./css/app.css | http://www.atguigu.com/course/css/app.css |
| js/app.js | http://www.atguigu.com/course/js/app.js |
| ../img/logo.png | http://www.atguigu.com/img/logo.png |
| ../../mp4/show.mp4 | http://www.atguigu.com/mp4/show.mp4 |
網(wǎng)頁(yè)中使用 URL 的場(chǎng)景小結(jié)
包括但不限于如下場(chǎng)景:
- a 標(biāo)簽 href
- link 標(biāo)簽 href
- script 標(biāo)簽 src
- img 標(biāo)簽 src
- video audio 標(biāo)簽 src
- form 中的 action
- AJAX 請(qǐng)求中的 URL
設(shè)置資源類型(mime類型)
媒體類型(通常稱為 Multipurpose Internet Mail Extensions 或 MIME 類型 )是一種標(biāo)準(zhǔn),用來(lái)表示文檔、文件或字節(jié)流的性質(zhì)和格式。
mime 類型結(jié)構(gòu): [type]/[subType]
例如: text/html text/css image/jpeg image/png application/json
HTTP 服務(wù)可以設(shè)置響應(yīng)頭 Content-Type 來(lái)表明響應(yīng)體的 MIME 類型,瀏覽器會(huì)根據(jù)該類型決定如何處理資源
下面是常見(jiàn)文件對(duì)應(yīng)的 mime 類型
html: 'text/html',
css: 'text/css',
js: 'text/javascript',
png: 'image/png',
jpg: 'image/jpeg',
gif: 'image/gif',
mp4: 'video/mp4',
mp3: 'audio/mpeg',
json: 'application/json'
對(duì)于未知的資源類型,可以選擇
application/octet-stream類型,瀏覽器在遇到該類型的響應(yīng)時(shí),會(huì)對(duì)響應(yīng)體內(nèi)容進(jìn)行獨(dú)立存儲(chǔ),也就是我們常見(jiàn)的下載效果
中文亂碼問(wèn)題:
①響應(yīng)頭mime類型后面指定編碼集:content-type: text/html; charset=UTF-8
②在主頁(yè)面HTML文件里面加上meta標(biāo)簽指定編碼集:<meta charset=UTF-8" />
③優(yōu)先級(jí):響應(yīng)頭>頁(yè)面 (一般不會(huì)設(shè)置不同)
④在頁(yè)面指定字符集后,頁(yè)面中加載的css、js、圖片等資源時(shí)可以不設(shè)置字符集默認(rèn)用主頁(yè)面字符集加載到頁(yè)面
GET 和 POST 請(qǐng)求場(chǎng)景小結(jié)
GET 請(qǐng)求的情況:
- 在地址欄直接輸入 url 訪問(wèn)
- 點(diǎn)擊 a 鏈接
- link 標(biāo)簽引入 css
- script 標(biāo)簽引入 js
- img 標(biāo)簽引入圖片
- form 標(biāo)簽中的 method 為 get (不區(qū)分大小寫(xiě))
- ajax 中的 get 請(qǐng)求
POST 請(qǐng)求的情況:
form 標(biāo)簽中的 method 為 post(不區(qū)分大小寫(xiě))
AJAX 的 post 請(qǐng)求
GET和POST請(qǐng)求的區(qū)別
GET 和 POST 是 HTTP 協(xié)議請(qǐng)求的兩種方式。
-
GET主要用來(lái)獲取數(shù)據(jù),POST主要用來(lái)提交數(shù)據(jù) -
GET帶參數(shù)請(qǐng)求是將參數(shù)綴到 URL 之后,在地址欄中輸入 url 訪問(wèn)網(wǎng)站就是 GET 請(qǐng)求,POST帶參數(shù)請(qǐng)求是將參數(shù)放到請(qǐng)求體中 -
POST請(qǐng)求相對(duì)GET安全一些,因?yàn)樵跒g覽器中參數(shù)會(huì)暴露在地址欄 -
GET請(qǐng)求大小有限制,一般為 2K,而 POST 請(qǐng)求則沒(méi)有