一句話:canonical request 是把 HTTP 請求「抄成一套嚴格固定格式」的六行文字,唯一目的是——讓你算的東西,跟 server 待會兒重算的東西,一個字元都不差。
因為簽章是「對一段文字做雜湊」,而 server 待會兒會照同樣規則再算一次來比對。兩邊的輸入文字必須一字不差,算出來才相等。差一個空格、大小寫、參數順序,雜湊就完全不同、簽章對不上。所以 AWS 把格式定死。
HTTPMethod ← GET / PUT / HEAD …
CanonicalURI ← 物件路徑,如 /test.txt
CanonicalQueryString ← query 參數:逐個 URL-encode、按 key 排序
CanonicalHeaders ← 至少含 host;名稱小寫、按字母排序;值去頭尾空白;每行以換行結尾
SignedHeaders ← 上面被簽的 header 名,小寫、分號連接
HashedPayload ← body 雜湊;presigned 用固定字串 UNSIGNED-PAYLOAD
GET
/test.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
host:examplebucket.s3.amazonaws.com
host
UNSIGNED-PAYLOAD
/→%2F),然後按 key 字母排序。順序錯、少編碼都會對不上。UNSIGNED-PAYLOAD,不是去算 body 的雜湊——因為簽 URL 時還不知道 body。一句話收尾:canonical request 就是「兩邊講好的標準抄法」。抄法一致,雜湊才會一致,簽章才對得上——這是整套 SigV4 能運作的前提。