網路流量與 HTTP Repeater
這個面板顯示的每一個字串都是硬寫在元件裡的英文。把網站切成繁體中文不會翻譯面板標題、欄位名稱、按鈕文字或空狀態文字——本頁引用的那些標籤,在中英文介面底下看到的都是同一組英文。
Network Traffic 面板
面板工具列左側固定顯示標題 Network Traffic。旁邊是目前的記錄筆數:剛好一筆時寫 1 request,其餘筆數(含零筆)一律寫 N requests。
工具列右側是一顆 Clear 按鈕。按下去會清空整份記錄、收合目前展開中的明細,並把編號歸零,所以 Clear 之後記錄到的下一筆是 1,不會接續先前的最大號碼。
還沒有任何記錄時,面板中央顯示 No requests recorded yet。
Network 面板是唯一不受就緒閘門管轄的工具面板。執行環境與 Service Worker 還在啟動時,四顆分頁按鈕全都點得動、每個分頁都切得過去——沒有任何一顆分頁按鈕會被停用。被停用的是內容:Browser、Repeater、Code 三個面板收到一個停用旗標,面板內的控制項因此變灰按不動。Network 面板從來不會收到這個旗標,所以照樣完全可以操作——只是還沒有任何流量可看。
欄位
清單固定有五欄,順序如下。
| 欄位 | 顯示什麼 |
|---|---|
# | 序號,從 1 開始,每記錄一筆遞增 |
Method | 該請求的 HTTP 方法 |
URL | 只有路徑與 query string,協定與主機名稱被去掉。記錄到的網址無法被解析時,原字串原樣顯示 |
Status | 回應的狀態碼,帶顏色 |
Time | 該請求的耗時,一個整數接上 ms |
沒有來源欄,也沒有時間戳欄位。每筆記錄裡確實存了時間戳,但表格不顯示它。
新記錄一律附加到清單最後,所以表格由上到下是由舊到新。
Time 是包住整個 dispatch 前後量測、再四捨五入成整數毫秒。本機回應很快時 0ms 是正常讀數,不代表出了問題。
狀態碼配色
Status 欄只依數值門檻上色。
| 狀態碼 | 顏色 |
|---|---|
| 500 以上 | 紅色 |
| 400 到 499 | 橘色 |
| 300 到 399 | 黃色 |
| 其餘,含 2xx 與 1xx | 綠色 |
顏色就只是一條繪製規則。想知道某個狀態碼說明了伺服器如何處理該請求,看知識庫的 HTTP 狀態碼。
哪些請求會被記錄
Browser 面板、Repeater 與 Code 編輯器三者的請求都經同一層 tracked dispatch 送出,因此三者都進同一份記錄。沒有任何已開放的面板被排除在外。
表格不會標示某筆記錄由哪個面板發出。來源面板確實有被記下來,但只寫進可匯出的攻擊 session,不會出現在你看到的那一列。要把記錄對回產生它的操作,就用序號與它在擷取順序中的位置。
面板裡呈現的這份記錄住在頁面的記憶體中。它沒有筆數上限也不會被裁切,會一直累積到你按 Clear 為止。它的範圍就是你目前所在的這個題目頁面:換頁、重新整理或切換語系都會讓整份記錄清空——切換語系等於導向另一語系的同一頁網址,整頁重新載入。
每一筆的完整內容(含 header 與請求、回應兩邊的內容)另外會被複製進該題的攻擊 session 並寫入 IndexedDB。那一份副本在重新整理後仍然存在,即使畫面上的清單已經空了,仍可由匯出的 session 讀到。
執行環境沒有 worker 可派送時,該請求不會消失。它會以狀態碼 503 被記錄下來,在清單中顯示為一列紅色。
讀一筆記錄
點一列會在該列正下方展開明細。再點同一列即收合。
明細區有 Request 與 Response 兩個子分頁,每次展開都停在 Request。
Request 把該筆重組成一封 raw HTTP 訊息:第一行是 方法 /路徑 HTTP/1.1 形式的請求行,接著是 header 行、一個空行,然後是請求內容。
那一段 header 不是 fetch 真的送得上線的那幾個。它是一組模擬 Chrome 的 header——Host、Connection、Sec-Ch-Ua、User-Agent、Accept、Sec-Fetch-* 這一家族——與程式實際送出的自訂 header 取聯集。不在模擬清單內的自訂 header 會被接在後面。請求帶了 cookie 時,模擬那一群的最後會多一行 Cookie。
Response 以 HTTP/1.1 <狀態碼> 起頭——本實驗室從來不填狀態文字那一格,這裡與 Repeater 的回應區都一樣——接著是回應 header、一個空行,然後是回應內容。伺服器設的 cookie 會被還原成一般的 Set-Cookie header 行,一個 cookie 一行。這個明細區塊有固定的高度上限,訊息超過時區塊內自行捲動。
子分頁列上方可能出現一塊開頭寫 Runtime diagnostic: 的紅框。只有 PHP 執行環境會發出它,內容是它在組出這份回應時丟掉了什麼——例如附在不能帶主體的狀態碼上的輸出,或題目試圖設定的保留 header。本 repo 現存題目的後端全是 Python,所以目前沒有任何一題產生得出這塊紅框。
Send to Repeater
Send to Repeater 按鈕位於子分頁列的最右端。它只存在於展開後的明細區內,所以要先展開某一列才看得到。
沒有開放 Repeater 分頁的題目根本不會繪製這顆按鈕。它是不存在,不是停用。
- 在流量清單中點你要的那一列。
- 在展開的明細區裡點
Send to Repeater。 - 畫面自動切換到 Repeater 分頁。
- 該筆的 raw 請求文字會覆蓋 Repeater 編輯區裡原本的內容。
對同一列連按兩次 Send to Repeater,第二次不會有作用。注入的值會與前一次比對,值相同就不觸發覆寫——分頁仍然會切過去,但你改過的內容留著。要拿回未經修改的原始請求,先展開另一列再回來,或還原一個 snapshot。
Repeater 面板
Repeater 以純文字編輯一整封 HTTP 訊息。沒有拆開的方法、網址、header、內容欄位。
| 控制項 | 行為 |
|---|---|
Raw HTTP Request 編輯區 | 單一的自由文字編輯區,容納完整訊息:請求行、header 行、一個空行,然後是內容 |
Send | 依你寫的內容原樣送出。執行環境或 Service Worker 尚未就緒時會變半透明且按不下去 |
| 回應區 | 顯示以 HTTP/1.1 <狀態碼> 起頭的回應——狀態文字那一格永遠是空的——接著 header、一個空行與回應內容 |
+ Save | 展開一列,提示 Snapshot name: 要求為即將儲存的 snapshot 命名 |
Saved Snapshots 側欄 | 列出已存的請求;沒有任何 snapshot 時顯示 No snapshots yet |
面板一開啟就已經填好一份 GET / HTTP/1.1 請求,Host 是 challenge-<題目 slug>.localhost,後面接著 User-Agent、Accept、Accept-Language、Accept-Encoding、Connection 等 header。
實際打出去的網址由 Host header 與請求行裡的路徑組成。把 Host 改成另一題的 slug,請求就送去那一題,而流量記錄裡對應的那一筆也會顯示改後的 Host。
請求格式
先寫請求行,之後每行一個 header,然後一個空行,最後是內容。
POST /items HTTP/1.1
Host: challenge-example.localhost
Content-Type: application/x-www-form-urlencoded
name=widget&quantity=2分隔 header 與內容的就是那個空行。少了它,內容文字會被讀成另一行 header。
在 raw 請求裡寫 Cookie header 是有效的。平台會以另一個 header 名稱把它載過邊界,在後端側還原之後題目才會看到它。
兩種看起來壞掉的情形
第一行是空的。 請求文字的第一行為空時,回應區顯示 Error: invalid request format,而且什麼都不會送出。
按 Send 完全沒反應。 只要第一行非空,這段文字就會被交給瀏覽器的 request 建構子。建構子若拒絕它——GET 或 HEAD 帶了內容(在分隔空行後多打一個換行就會發生),或方法名不是合法 token——這個失敗不會被接住。回應區既不更新也不顯示錯誤訊息,於是 Send 看起來完全沒作用。在斷定題目掛掉之前,先檢查第一行與結尾多出來的換行。
回應區與 Network 面板的差異
Repeater 的回應區直接把瀏覽器暴露的 header 原樣印出來,因此每個 header 名稱都是小寫。伺服器設的 cookie 在這裡不會被還原:它們以單一一個 x-wxlsh-set-cookie header 出現,值是一串以逗號分隔的 base64——那是平台用來把 cookie 載過邊界的載送 header,而 Repeater 在它被拆開之前就印出來了。
同一筆交換在 Network 面板的 Response 分頁裡卻是拆開後的 Set-Cookie 行。因此同一次往返在兩處看起來不一樣;要看正常形式的 cookie 就讀 Network 面板那一份。
Snapshot
- 編輯區裡放好你要的請求,點
+ Save。 - 在出現的那一列輸入名稱。
Enter確認,Escape取消。 - 名稱空白或只有空白字元時按下去沒有作用——儲存列會一直開著,直到你輸入真正的名稱或按
Escape。
snapshot 只保存請求文字,不會連同回應一起存。
點 Saved Snapshots 側欄裡的 snapshot 名稱,會把它的內容寫回編輯區,覆蓋目前的文字。滑鼠移到某個 snapshot 上會浮出一顆 ×,按下即刻刪除該筆,沒有確認步驟。
snapshot 存在瀏覽器的 localStorage,key 含題目 slug。關掉分頁重開仍然在,而且某一題存的 snapshot 不會出現在另一題。
走查範例:改一個參數再比對
以下示範這趟往返的操作機制。它不以任何東西為標的,也不對應用程式下任何結論——重點是點哪裡、比對什麼。
- 在 Browser 面板做任何一個會發出請求的動作,例如送出表單或點一個帶 query string 的連結。
- 開啟 Network 分頁。該請求會以新的一列出現在清單最下方。記下它的
Status與Time。 - 點那一列。在
Request子分頁讀那封 raw 訊息,找到你想改動的那個參數。 - 點
Send to Repeater。畫面切到 Repeater,該封訊息已經載入。 - 點
+ Save,為 snapshot 命名後按Enter。這給你一條回到未修改請求的路。 - 在
Raw HTTP Request編輯區改掉一個參數的值,其餘一律不動。 - 點
Send。回應區會填入狀態行、header 與回應內容。 - 與原本那一筆比對:狀態碼、header 集合、以及回應內容的長度或內容本身。改一個參數、觀察一個差異,這就是一個完整的工作單位。
- 切回 Network 分頁。重送的那個請求以自己的一列在記錄裡,你可以在那裡讀到還原後的
Set-Cookieheader 與記下的Time。
要試第二種變化,點側欄裡的 snapshot 還原原始文字,再從步驟 6 重來。
面板行為不如預期時
流量記錄一片空白、Send 按鈕一直停用、第一次載入等很久,這些都有已知的成因。它們連同各自的症狀與處理方式列在疑難排解。