National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 78 24°C PM2.5 18
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 13

HTTP:取得網路資料與網頁伺服器

urequests 取資料、在 ESP32 上跑簡單的網頁伺服器
Interaction 30 minute(s)

Learning Objectives

  • 說明一次 HTTP 請求與回應包含哪些部分,以及 200、201、404 這些狀態碼的意思
  • 用 urequests.get 取得 JSON 資料並轉成字典,用 urequests.post 上傳感測值
  • 用 try/except 與狀態碼處理網路錯誤,用完記得 close()
  • 用 socket 在 ESP32 上寫一個簡單的網頁伺服器,依網址路徑控制 LED

和網路服務說同一種語言

上一課 ESP32 連上了 Wi-Fi,但只是「連上」還不夠,還要能和網路上的服務交換資料。 瀏覽器打開網頁、手機 App 查天氣,背後大多是 HTTP:一方送出請求(request),另一方回傳回應(response)。

這一課 ESP32 兩種角色都當一次:

  1. 用戶端:向天氣服務要資料、把感測值上傳到伺服器(用 urequests)
  2. 伺服器:讓同一個網路裡的手機用瀏覽器開關 LED(用 socket)

HTTP 長什麼樣子

HTTP 是純文字的格式。瀏覽器打開 http://192.168.1.42/led/on 時,送出的請求大致是:

GET /led/on HTTP/1.1          ← 請求行:方法、路徑、版本
Host: 192.168.1.42            ← 標頭(header),一行一個
                              ← 空行:標頭結束

伺服器的回應:

HTTP/1.1 200 OK               ← 狀態行:版本、狀態碼、說明
Content-Type: text/html       ← 標頭:內容是 HTML
                              ← 空行
<h1>LED: ON</h1>              ← 內容(body)

每一行用 \r\n 結束,標頭和內容之間隔一個空行。

常見的方法 用途
GET 取得資料(查天氣、打開網頁)
POST 送出資料(上傳感測值、送出表單)
常見的狀態碼 意思
200 OK 成功
201 Created 成功,而且建立了一筆新資料
404 Not Found 找不到這個路徑
500 Internal Server Error 伺服器自己出錯

本課的 api.example.com 是虛構的服務。example.com 是 RFC 2606 保留給文件與範例用的網域,不屬於任何真實服務, 模擬器裡的回應是事先設定好的。

JSON:網路服務常用的資料格式

網路服務回傳的資料大多是 JSON(JavaScript Object Notation),和 Python 的字典、串列長得幾乎一樣:

{"city": "Taoyuan", "temp": 27.5, "hourly": [{"hour": 15, "temp": 28}, {"hour": 18, "temp": 26}]}
JSON Python
{ } 物件 字典 dict
[ ] 陣列 串列 list
"文字" 字串 str
27.5、28 浮點數、整數
true/false/null True/False/None

MicroPython 用 urequests 模組送 HTTP 請求,回應物件 r 有這些常用的東西:

寫法 得到
r.status_code 狀態碼,例如 200
r.text 回應內容(字串)
r.json() 把 JSON 內容轉成字典或串列
r.close() 關閉連線、釋放記憶體

ESP32 的記憶體不多,每次用完都要 close(),不然連續請求幾次之後可能會記憶體不足。

這個模組在 micropython-lib 裡已經改名為 requests,舊名稱 urequests 保留下來讓舊程式繼續能用。 本課用 urequests,網路上的範例兩種寫法都會看到,用法相同。

逐步看:取得天氣資料

先連上 Wi-Fi(上一課的寫法),再送出 GET 請求。電路畫面下方的網路紀錄會出現送出的請求; 注意第 11 行花了一段時間:請求要經過網路送到伺服器,再等回應回來。

逐步看:上傳感測值,處理網路錯誤

upload() 用 POST 把一筆讀值送到伺服器。程式故意先在還沒連網時呼叫一次,看 try/except 怎麼接住錯誤;連網之後再呼叫一次。

換個角色:ESP32 當網頁伺服器

反過來,讓 ESP32 等別人連進來。這要用比較底層的 socket(通訊端),步驟固定是:

步驟 程式 意思
1 socket.getaddrinfo("0.0.0.0", 80)[0][-1] 取得「本機所有網路介面、第 80 埠」的位址;80 是 HTTP 預設的連接埠
2 s.bind(addr)、s.listen(1) 綁定位址,開始等待連線
3 cl, remote = s.accept() 停在這裡,直到有瀏覽器連進來,得到這次連線的 cl
4 cl.recv(1024) 讀取請求(bytes)
5 cl.send(...) 送出狀態行、標頭、空行、內容
6 cl.close() 關閉這次連線,回到第 3 步等下一個

MicroPython 官方教學的網頁伺服器範例也是這個結構。請求的第一行是 GET /led/on HTTP/1.1, 用空白切開,索引 1 就是路徑,程式依路徑決定要做什麼。

真的開發板上,你在同一個 Wi-Fi 的手機瀏覽器輸入 ESP32 的 IP 位址(例如 http://192.168.1.42/led/on)就能連進來。 模擬器裡,瀏覽器的請求依電路規格的時間表送來:1 秒開燈、2 秒看首頁、3 秒關燈。

這種伺服器一次只服務一個連線,也沒有任何密碼保護,只適合在自己的區域網路裡做實驗,不要讓它暴露在公開的網際網路上。

逐步看:用網址開關 LED

看程式停在第 20 行 accept():時間直接跳到下一個請求到達的時刻。每處理完一個請求,網路紀錄會多一筆「回應」。最後一個請求處理完,程式又停在 accept() 等待,直到模擬時間結束。

互動練習:完成 LED 網頁伺服器

起始程式只會處理 /led/on,而且不管收到什麼都回「OK」。模擬的瀏覽器會依序送來四個請求: 0.8 秒 /led/on、1.8 秒 /led/off、2.8 秒 /status、3.8 秒 /nothing。依序完成任務:

  1. 先直接執行,看 LED 亮起、網路紀錄出現回應。
  2. 處理 /led/off:把 LED 關掉。
  3. 處理 /status:回應的內容是 LED is ON 或 LED is OFF(依 LED 目前的狀態)。
  4. 其他不認得的路徑,回應狀態行改成 HTTP/1.1 404 Not Found。
  5. 回答一個問題。

小測驗:HTTP 與 JSON

1.

伺服器回應的第一行是 HTTP/1.1 404 Not Found,代表什麼?

2.

下面的程式會印出什麼?(r.json() 回傳的就是這樣的字典)

import json
text = '{"city": "Taoyuan", "hourly": [{"hour": 15, "temp": 28}, {"hour": 18, "temp": 26}]}'
data = json.loads(text)
print(data["hourly"][1]["temp"], len(data["hourly"]))
3.

要把感測器讀值送到伺服器存起來,通常用哪一種方法?

第 1 次作答

小測驗:網頁伺服器

1.

下面的程式會印出什麼?

request = "GET /led/off HTTP/1.1\r\nHost: 192.168.1.42\r\n\r\n"
path = request.split(" ")[1]
print(path, path.startswith("/led"))
2.

網頁伺服器程式執行到 cl, remote = s.accept(),還沒有人連進來,這時程式在做什麼?

3.

回應要寫成 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" 再接內容。最後為什麼有兩組 \r\n?

第 1 次作答

重點整理

  • HTTP 是一來一回的文字格式:請求行(方法、路徑)+標頭+空行+內容;回應用狀態碼表示結果(200、201、404…)。
  • r = urequests.get(網址)、urequests.post(網址, json=字典);r.status_code、r.text、r.json(),用完 r.close()。
  • 網路操作包在 try/except OSError 裡,失敗時程式不會停,可以稍後重試。
  • 網頁伺服器:bind → listen → 迴圈裡 accept(會等待)→ recv 讀請求 → 依路徑處理 → send 回應 → close。
  • 這種簡單的伺服器沒有密碼保護,只在自己的區域網路裡實驗。

下一課介紹物聯網常用的 MQTT:不用一直問伺服器,有新訊息時會主動送到。

這一課完成了!
Next lesson:MQTT 物聯網通訊
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。