Ngiêm cấm sử đụng PROXY và VPS vào mục đích trái pháp luật bạn sẽ phải chịu toàn bộ trách nhiệm trước pháp luật khi sử dụng dịch vụ của chúng tôi tks!
HTTP 428 Precondition Required: thêm If-Match theo ETag

HTTP 428 Precondition Required: thêm If-Match theo ETag

Chuyên viên Kỹ thuật ProxyVN 03-27-2026 Đang tính... phút đọc

HTTP 428 Precondition Required là mã server dùng để nói: tôi không nhận yêu cầu ghi này nếu anh không kèm điều kiện. Mục đích là chặn lỗi ghi đè mất dữ liệu khi nhiều bên cùng sửa một tài nguyên. ProxyVN dựng một API lab có version và ETag, chạy requests và httpx thật với nhiều biến thể If-Match. Lab còn tái hiện hai worker cùng ghi một bản ghi để thấy cơ chế chặn ghi đè hoạt động ra sao.

HTTP 428 Precondition Required: mục tiêu và phạm vi không lặp

Phần này chốt bài toán và ranh giới với các bài đã có.

Bài toán cần giải

Một pipeline đồng bộ giá đẩy dữ liệu lên API quản lý sản phẩm bằng PUT. Sau khi API bật yêu cầu ghi có điều kiện, mọi request bỗng trả 428. Người vận hành nghĩ API hỏng hoặc proxy chặn, thử đổi IP, thử thêm header ngẫu nhiên. Thực ra server chỉ đang đòi client chứng minh mình sửa đúng bản mới nhất.

Đầu ra nghiệm thu

Đầu ra là một lab ghi lại bốn kết quả cốt lõi. Ghi không điều kiện bị từ chối với 428. If-Match đúng version được chấp nhận và nhận ETag mới. If-Match theo version cũ bị từ chối với 412. Hai worker ghi đồng thời thì chỉ một bên thắng. Kèm theo là hàm cập nhật có đọc lại và thử lại.

Ranh giới với bài 409

Bài lỗi 409 Conflict khi gọi API đã giải thích khác biệt giữa 409 và 412 và nhắc tới If-Match. Bài này không lặp phần đó. Nó tập trung vào mã 428: lúc nào xuất hiện, client thêm điều kiện thế nào, và vì sao 428 khác với điều kiện đã gửi nhưng không thỏa.

Không phải bài lỗi 4xx chung

Bài không giải thích các mã 4xx khác. Mọi ví dụ đều xoay quanh một tài nguyên có version và ETag, một method ghi, và header If-Match. Nếu API của anh em dùng version trong body thay vì ETag, phần lớn bài vẫn áp được, nhưng cơ chế đúng phải đọc trong tài liệu của API đó.

Giới hạn của lab

API là máy chủ Python tự viết bằng http.server, nghe ở 127.0.0.1:9741, lưu một sản phẩm sku-1 trong bộ nhớ. ETag có dạng "v" kèm số version. Quy tắc so khớp lab viết theo RFC 9110. Thứ thật trong lab là hai thư viện client và các header chúng gửi. API thật có thể sinh ETag theo hash nội dung và kèm thông báo lỗi khác.

Ai nên đọc

Người viết pipeline ghi dữ liệu vào API có kiểm soát đồng thời, như API thương mại điện tử, CMS, kho dữ liệu cấu hình. Người viết worker song song cùng sửa một tập bản ghi. Người gặp 428 lần đầu và cần biết sửa phía client thế nào.

Chẩn đoán HTTP 428 Precondition Required và thêm điều kiện cập nhật API có version

Phần này tóm tắt chuẩn, chỉ giữ ý cần cho client.

Định nghĩa trong RFC 6585

Theo RFC 6585 mục 3, mã 428 cho biết origin server yêu cầu request phải có điều kiện. Cách dùng điển hình là tránh lỗi lost update: client GET trạng thái, sửa, rồi PUT lại, trong khi một bên thứ ba đã sửa trạng thái trên server, gây xung đột.

Server nên giải thích cách gửi lại

RFC ghi phản hồi 428 nên giải thích cách gửi lại request cho thành công. Ví dụ trong RFC là trang HTML nói request phải có điều kiện, hãy thử dùng If-Match. Trong API JSON, phần giải thích thường nằm ở problem details hoặc trường thông báo lỗi. Lab dùng problem details với detail nói rõ phải gửi If-Match lấy từ ETag của GET gần nhất.

Không được lưu cache

RFC yêu cầu phản hồi 428 không được cache lưu lại. Lý do dễ hiểu: 428 phụ thuộc vào request cụ thể có điều kiện hay không, lưu lại sẽ trả sai cho request sau có điều kiện. API lab gửi kèm Cache-Control: no-store cho 428 như một biện pháp thêm.

If-Match trong RFC 9110

If-Match so khớp mạnh

If-Match so khớp mạnh

Theo RFC 9110 mục 13.1.1, If-Match làm method có điều kiện. Với giá trị dấu sao, điều kiện đúng khi server có bất kỳ đại diện hiện hành nào. Với danh sách ETag, điều kiện đúng khi một ETag trong danh sách khớp ETag của đại diện hiện hành.

So khớp mạnh

RFC yêu cầu origin server dùng phép so mạnh khi đánh giá If-Match, vì client muốn chặn method nếu đại diện có bất kỳ thay đổi nào. Phép so mạnh nghĩa là ETag yếu, có tiền tố W/, không bao giờ khớp. Đây là điểm hay bị bỏ qua khi server trả ETag yếu do nén nội dung động.

Điều kiện sai thì không thực hiện

RFC nói server đánh giá If-Match ra sai thì không được thực hiện method. Server có thể trả 412 Precondition Failed. RFC cũng cho phép trả 2xx nếu thay đổi có vẻ đã được áp dụng trước đó, ví dụ phản hồi lần trước bị mất. Lab chọn cách chặt: luôn trả 412 khi không khớp.

428 và 412 khác nhau ở đâu

Hai mã này dễ nhầm vì tên gần giống. 428 nói request thiếu điều kiện. 412 nói request có điều kiện nhưng điều kiện không thỏa. Cách sửa vì vậy khác nhau: 428 sửa mã client để luôn gửi điều kiện, 412 đọc lại tài nguyên rồi quyết định có ghi tiếp không.

Bảng: 428 và 412 khác nhau ở đâu

Mã

Request có điều kiện?

Ý nghĩa

Client làm gì

428

Không

Server bắt buộc có điều kiện

Sửa mã, GET lấy ETag, gửi If-Match

412

Có

Điều kiện không thỏa, tài nguyên đã đổi

GET lại, hợp nhất thay đổi, thử lại có giới hạn

409

Tùy

Xung đột trạng thái theo quy tắc nghiệp vụ

Đọc body lỗi, xử lý theo nghiệp vụ

200

Có, khớp

Ghi thành công

Lưu ETag mới cho lần sau

Điều kiện khác ngoài If-Match

RFC 9110 có các header điều kiện khác như If-Unmodified-Since, If-None-Match, If-Modified-Since. Với ghi có điều kiện, If-Match và If-Unmodified-Since là hai lựa chọn chính. If-Match chính xác hơn vì so theo ETag, còn thời gian chỉ chính xác tới giây. Server tự chọn chấp nhận header nào, và phải ghi trong tài liệu.

Lost update xảy ra thế nào

Worker A đọc giá và tồn kho, worker B cũng đọc cùng lúc. A sửa giá, ghi lên. B sửa tồn kho, ghi lên với nguyên giá cũ đã đọc. Kết quả: thay đổi giá của A biến mất. Không ai báo lỗi, vì cả hai request đều hợp lệ. Đây là loại lỗi chỉ phát hiện khi đối chiếu dữ liệu với nguồn gốc.

Đổi IP không sửa được 428

428 là quyết định của ứng dụng dựa trên header của request. Proxy chuyển tiếp không thêm If-Match, không bỏ If-Match. Đổi IP, đổi proxy, đổi User-Agent đều không làm 428 biến mất. Cách duy nhất là gửi đúng điều kiện.

Tạo resource có version và ETag trên server lab cho HTTP 428 Precondition Required

Phần này dựng API lab, chạy thật trên Python 3.12.10.

Dữ liệu và ETag

API giữ một từ điển với sku-1 ở version 3, giá 199.000, tồn kho 12. ETag sinh từ version theo dạng chuỗi trong ngoặc kép.

DB = {"sku-1": {"version": 3, "data": {"price": 199000, "stock": 12}}}
 
def etag(v):
    return f'"v{v}"'

ETag theo version là cách đơn giản. API thật có thể dùng hash nội dung, đều hợp lệ miễn là đổi khi đại diện đổi.

GET trả ETag

GET trả dữ liệu kèm ETag và Cache-Control: no-cache. Client cần ETag này cho lần ghi sau. no-cache buộc cache trung gian phải xác thực lại trước khi dùng bản lưu, để client không nhận ETag cũ từ cache.

GET    200 etag="v3" cc=no-cache ct=application/json body={'price': 199000, 'stock': 12}

Đây là output thật của requests 2.34.2.

PUT đánh giá điều kiện trong khóa

Toàn bộ phần đọc version, so ETag và ghi nằm trong một khóa luồng. Không có khóa, hai request đến cùng lúc có thể cùng thấy version 6, cùng khớp, cùng ghi. Đó chính là lost update mà If-Match muốn chặn, nhưng chuyển xuống phía server.

with LOCK:
    r = DB.get(k)
    if im is None:
        return self.send(428, {...}, [("Cache-Control", "no-store")])
    cur = etag(r["version"])
    tags = parse_list(im)
    ok = (im.strip() == "*") or any(t == cur for t in tags)
    if not ok:
        return self.send(412, {..., "current_etag": cur})
    r["version"] += 1; r["data"] = body
    self.send(200, {"id": k, **body}, [("ETag", etag(r["version"]))])

Dấu ba chấm thay cho body problem details, xem đầy đủ trong mã lab.

So khớp mạnh trong mã

Phép so trong lab là so chuỗi bằng nhau, nên W/"v4" không bao giờ khớp "v4". Đây là cách triển khai đúng tinh thần phép so mạnh, vì ETag lab luôn là ETag mạnh. Với API có cả ETag yếu, server phải tách phần W/ và áp đúng quy tắc của RFC.

Phản hồi 200 có ETag mới

Sau mỗi lần ghi thành công, API lab trả ETag mới. RFC cho server quyền không trả ETag trong phản hồi thành công, khi muốn client GET lại để nắm đúng trạng thái. Client không nên giả định ETag mới luôn có. Không có thì GET lại trước lần ghi kế tiếp.

Body lỗi có ETag hiện hành

Phản hồi 412 của lab có trường mở rộng current_etag. RFC không bắt server gửi trường này. Nhiều API không gửi để tránh lộ trạng thái. Có thì client đỡ một lần GET, không có thì client GET lại. Hàm cập nhật ở phần sau không dựa vào trường này.

Không cần proxy cho lab

API lab chạy trên máy cục bộ, client gọi thẳng. Hành vi 428 nằm ở ứng dụng, không phụ thuộc đường mạng. Bài chỉ nhắc tới proxy ở phần cuối, khi pipeline thật cần đi qua một đường mạng cụ thể.

Tách luồng đọc và luồng ghi

Pipeline crawl thường đọc ở một nơi, ghi ở nơi khác, cách nhau vài phút. Khoảng cách đó làm ETag dễ cũ. Lưu ETag cùng dữ liệu đã đọc, và khi ghi thì dùng đúng ETag đi kèm dữ liệu đó. Nếu chỉ lưu dữ liệu mà không lưu ETag, lúc ghi buộc phải GET lại, và mất luôn ý nghĩa của điều kiện.

Vì sao dùng PUT

PUT thay toàn bộ đại diện, nên rủi ro lost update rõ nhất: worker B ghi đè cả trường mà worker A vừa sửa. PATCH chỉ sửa một phần nhưng vẫn có thể xung đột khi hai bên sửa cùng trường. Cơ chế If-Match áp cho cả hai method.

Gửi update thiếu precondition để nhận HTTP 428 Precondition Required

Phần này chạy ca gốc của bài.

PUT không có If-Match

requests gửi PUT với giá mới 189.000, không có If-Match. API trả 428, content type application/problem+json, Cache-Control: no-store, không có ETag.

PUT khong If-Match   428 etag=None cc=no-store ct=application/problem+json body={'title': 'Precondition Required'}

Tài nguyên không đổi. Version vẫn là 3.

Thư viện biết tên mã

requests trả reason Precondition Required. httpx trả reason_phrase Precondition Required, is_client_error True, raise_for_status ném lỗi "Client error '428 Precondition Required'". Cả hai không tự thêm If-Match, không tự thử lại. Đây là hành vi đúng, vì thư viện không biết ETag nào phù hợp.

Body giải thích cách sửa

Body 428 của lab có detail "PUT phai co If-Match lay tu ETag cua GET gan nhat". Đọc body là cách nhanh nhất để biết server cần điều kiện nào. Có API đòi If-Match, có API chấp nhận If-Unmodified-Since. Chỉ nhìn mã 428 không đủ để biết.

Xem header Allow và tài liệu

Một số API kèm liên kết tới tài liệu trong body 428, hoặc ghi header nào được chấp nhận. Nếu body không nói gì, xem tài liệu API phần concurrency hoặc optimistic locking. Tên gọi khác nhau giữa các nhà cung cấp, nhưng gần như luôn xoay quanh ETag và If-Match.

Ghi log 428 như lỗi của client

428 là dấu hiệu mã client chưa theo kịp yêu cầu của API, không phải sự cố tạm thời. Pipeline nên xếp 428 vào nhóm lỗi cần sửa mã, báo người phát triển, không đưa vào hàng thử lại tự động. Thử lại không có If-Match sẽ chỉ nhận thêm 428.

Bắt 428 trong test

Test tích hợp của pipeline nên có một ca gửi PUT không điều kiện và kỳ vọng 428, nếu API công bố là bắt buộc. Khi bên API tắt yêu cầu này, test đổi màu và anh em biết ngay. Ngược lại, khi bật mà mã chưa sửa, test cũng bắt được trước khi chạy thật.

Khi nào 428 xuất hiện bất ngờ

Thường là sau khi bên API bật chế độ ghi có điều kiện cho một nhóm endpoint. Script cũ chạy tốt nhiều tháng bỗng hỏng toàn bộ. Nếu log ghi lại thời điểm 428 đầu tiên, việc đối chiếu với thông báo thay đổi của API sẽ nhanh hơn nhiều.

Chưa chạm dữ liệu

Điểm tốt của 428: server từ chối trước khi làm gì. Không có ghi dở, không có trạng thái nửa vời. Client chỉ cần sửa và gửi lại. So với lỗi giữa chừng của một giao dịch dài, đây là lỗi dễ xử lý nhất.

Thử If-Match với version đúng và version cũ cho HTTP 428 Precondition Required

Phần này chạy các biến thể của If-Match.

If-Match đúng

If-Match đúng và cũ

If-Match đúng và cũ

Gửi lại PUT với If-Match "v3" lấy từ GET. API trả 200 kèm ETag "v4", dữ liệu mới có giá 189.000. Client cần lưu ETag mới này nếu định ghi tiếp.

PUT If-Match dung "v3"   200 etag="v4" body={'price': 189000, 'stock': 12}
PUT lai If-Match cu "v3" 412 body={'title': 'Precondition Failed', 'current_etag': '"v4"'}

Dòng thứ hai là phép thử ngay sau đó với ETag cũ.

If-Match cũ nhận 412

Gửi lại PUT với cùng If-Match "v3" sau khi tài nguyên đã lên v4. API trả 412 với current_etag "v4". Tài nguyên không đổi. Đây chính là cơ chế chặn ghi đè: một bên cầm bản cũ không thể ghi lên bản mới.

ETag yếu không khớp

Gửi If-Match W/"v4" khi ETag hiện hành là "v4". API trả 412. Theo quy tắc so mạnh của If-Match, ETag yếu không bao giờ khớp. Nếu API thật trả ETag yếu ở GET, client sẽ không bao giờ ghi được bằng If-Match. Gặp trường hợp này, báo bên API, đừng tự bỏ tiền tố W/.

Thiếu ngoặc kép

Gửi If-Match v4 không có ngoặc kép. API trả 412, vì cú pháp ETag theo RFC bắt buộc có ngoặc kép, và lab so cả chuỗi. Lỗi này hay gặp khi lập trình viên gõ tay hoặc khi một lớp trung gian bỏ dấu ngoặc. Luôn lấy nguyên chuỗi ETag từ header, không dựng lại.

Gửi lại sau khi mất phản hồi

Giả sử PUT với "v3" đã được server áp dụng nhưng phản hồi bị mất vì mạng. Client gửi lại với "v3", nhận 412 vì tài nguyên đã lên v4. Đây không phải xung đột thật. Client nên GET, so dữ liệu với thay đổi định áp, thấy khớp thì coi là đã thành công. RFC có nhắc server có thể trả 2xx trong ca này, lab không mô phỏng.

Danh sách ETag

Gửi If-Match "v1", "v4". API trả 200, ETag mới "v5". RFC cho phép danh sách, điều kiện đúng khi một phần tử khớp. Trường hợp dùng thực tế hiếm, có thể khi client giữ vài bản đã biết là an toàn để ghi đè.

Dấu sao

Gửi If-Match *. API trả 200, ETag mới "v6". Dấu sao chỉ yêu cầu tài nguyên tồn tại, không bảo vệ khỏi ghi đè. Nó qua được cửa 428, nhưng mất hết lợi ích của 428. Dùng dấu sao chỉ để làm 428 biến mất là sửa sai cách.

Thứ tự kiểm khi nhận 412 liên tục

Nếu If-Match tưởng đúng mà vẫn nhận 412, kiểm lần lượt: ETag có tiền tố W/ không, có còn ngoặc kép không, GET có đi qua cache trả bản cũ không, có worker khác đang ghi cùng tài nguyên không. Bốn câu hỏi này giải quyết gần hết trường hợp gặp ở pipeline.

Bảng kết quả

Bảng dưới gom các phép thử với output thật của lab.

Bảng: Bảng kết quả

Request

If-Match

Kết quả

ETag sau

PUT

không có

428

"v3"

PUT

"v3"

200

"v4"

PUT

"v3" lần nữa

412

"v4"

PUT

W/"v4"

412

"v4"

PUT

v4 không ngoặc

412

"v4"

PUT

"v1", "v4"

200

"v5"

PUT

*

200

"v6"

Ghi ETag cùng kết quả

Mỗi lần ghi thành công, lưu ETag mới cạnh bản dữ liệu đã gửi trong kho của pipeline. Lần chạy sau dùng ETag này cho If-Match nếu chưa có ai sửa. Nếu nhận 412, nghĩa là có bên khác đã ghi kể từ lần mình ghi cuối, và đó là thông tin đáng ghi vào log.

Lost update giữa hai worker

Hai worker cùng ghi

Hai worker cùng ghi

Hai worker A và B cùng GET, cùng nhận "v6". A ghi giá 160.000 với If-Match "v6", nhận 200 và "v7". B ghi tồn kho 0 với cùng If-Match "v6", nhận 412, current_etag "v7". Không có If-Match, B đã ghi đè giá của A về 169.000 mà không ai hay.

worker A: 200 "v7" | worker B: 412 "v7"

Đây là phép thử trọng tâm: 412 không phải lỗi cần giấu, nó là cơ chế đang bảo vệ dữ liệu.

Phân biệt HTTP 428 Precondition Required với lỗi điều kiện không thỏa

Phần này viết hàm cập nhật xử lý đúng cả hai mã.

Hàm cập nhật có đọc lại

Hàm dưới GET lấy ETag, áp thay đổi lên dữ liệu vừa đọc, PUT với If-Match. Nhận 412 thì đọc lại và thử lại có giới hạn. Nhận 428 thì dừng, vì đó là lỗi mã.

def update_with_retry(session, url, change, tries=3):
    for i in range(1, tries + 1):
        g = session.get(url); cur = g.json(); tag = g.headers.get("ETag")
        if not tag:
            raise RuntimeError("API khong tra ETag: khong the gui If-Match")
        new = change({k: cur[k] for k in ("price", "stock")})
        r = session.put(url, json=new, headers={"If-Match": tag})
        if r.status_code == 200:
            return r.json(), r.headers["ETag"]
        if r.status_code == 428:
            raise RuntimeError("thieu precondition: loi cua client, sua ma")
        if r.status_code != 412:
            r.raise_for_status()
    raise RuntimeError("van xung dot sau %d lan" % tries)

Hàm nhận một hàm change áp thay đổi lên bản mới nhất, không phải một bản dữ liệu dựng sẵn.

Vì sao truyền hàm change

Nếu truyền dữ liệu dựng sẵn, lần thử lại sẽ ghi lại đúng dữ liệu cũ, và lost update vẫn xảy ra, chỉ chậm hơn một nhịp. Truyền hàm change buộc mỗi lần thử phải áp thay đổi lên bản vừa đọc. Worker B trong lab chỉ đặt stock về 0, giữ nguyên giá 160.000 mà A vừa ghi.

Kết quả thật

Worker B chạy hàm, lần 1 gửi If-Match "v7", nhận 200. Kết quả cuối có giá 160.000 và tồn kho 0, ETag "v8". Cả hai thay đổi đều còn.

lan 1: If-Match "v7" -> 200
({'id': 'sku-1', 'price': 160000, 'stock': 0}, '"v8"')

Version cuối của tài nguyên là 8, server nhận tổng 12 PUT trong cả lab.

Khi nào không nên tự hợp nhất

Hàm change hợp nhất được khi hai thay đổi chạm trường khác nhau. Nếu hai bên cùng sửa giá, tự động lấy bản sau có thể sai về nghiệp vụ. Pipeline nên phân biệt trường an toàn để hợp nhất và trường cần người duyệt, rồi đưa ca thứ hai vào hàng chờ xem xét.

API không trả ETag

Hàm dừng ngay nếu GET không có ETag. Một số API yêu cầu điều kiện bằng If-Unmodified-Since với Last-Modified, hoặc bằng trường version trong body. Đọc tài liệu API và viết biến thể riêng. Đừng tự chế ETag từ thời gian cục bộ.

Giới hạn số lần thử

Ba lần là con số của lab. Với tài nguyên bị sửa liên tục, có thể không bao giờ thắng. Khi vượt giới hạn, ghi lại tài nguyên, ETag cuối và thay đổi định áp, rồi chuyển cho người xem. Thử lại vô hạn chỉ làm tăng tải và che đi vấn đề thiết kế.

Proxy có thể làm mất ETag không

Proxy chuyển tiếp thông thường giữ nguyên ETag và If-Match. Một số proxy nén hoặc biến đổi nội dung có thể đổi ETag mạnh thành ETag yếu, vì đại diện đã khác. Nếu GET qua proxy cho ETag yếu mà gọi thẳng cho ETag mạnh, nguyên nhân nằm ở lớp biến đổi đó.

Hai mã, hai đường xử lý

Tóm gọn quy tắc của hàm: 428 là lỗi của mã, sửa một lần là hết. 412 là trạng thái bình thường của hệ có nhiều người ghi, xử lý mỗi ngày. Xếp chung hai mã vào một nhánh sẽ hoặc thử lại vô ích với 428, hoặc báo động giả với 412.

428 hỏi anh em có điều kiện không. 412 trả lời điều kiện của anh em đã cũ.

Đo tỷ lệ 412

Tỷ lệ 412 trên tổng số lần ghi là chỉ số tốt về mức tranh chấp. Tỷ lệ thấp là bình thường. Tỷ lệ tăng đột ngột có thể do thêm worker, do lịch chạy chồng lên nhau, hoặc do một hệ khác bắt đầu ghi cùng dữ liệu. Chỉ số này giúp phát hiện trước khi hàng chờ người duyệt đầy lên.

Giảm tranh chấp từ thiết kế

Cách tốt hơn thử lại là để mỗi tài nguyên chỉ có một worker ghi tại một thời điểm, ví dụ chia theo mã sản phẩm. If-Match vẫn giữ làm lưới an toàn. Khi tranh chấp hiếm, hàm cập nhật gần như luôn thắng ở lần đầu, như worker B trong lab.

Ghi log đủ để tra

Mỗi lần ghi nên log: tài nguyên, ETag gửi, mã nhận, ETag mới hoặc ETag hiện hành nếu có, số lần thử. Khi có tranh chấp, log này cho thấy worker nào thắng ở version nào, giúp tái hiện lại chuỗi sự kiện.

Đầu ra nghiệm thu của HTTP 428 Precondition Required: lab write và If-Match đúng sai

Phần này gom tiêu chí và giới hạn.

Danh sách kiểm tra

Danh sách nghiệm thu

Danh sách nghiệm thu

Client đạt khi mọi dòng dưới đây đúng trên API của anh em.

  • PUT không điều kiện nhận 428 và không làm đổi tài nguyên.
  • Mọi lần ghi lấy ETag từ GET gần nhất, giữ nguyên chuỗi.
  • If-Match đúng nhận 2xx và ETag mới được lưu lại.
  • If-Match cũ nhận 412, tài nguyên không đổi.
  • Hàm cập nhật áp thay đổi lên bản vừa đọc mỗi lần thử.
  • 428 không vào hàng thử lại tự động.
  • Không dùng If-Match dấu sao để né 428.

Kiểm cả DELETE

Xóa nhầm tài nguyên vừa được sửa cũng là một dạng lost update. API bật 428 cho PUT thường bật cho DELETE. Hàm xóa nên gửi If-Match giống hàm cập nhật. Lab chưa chạy DELETE, nhưng cơ chế so khớp không khác.

Những gì lab chưa chạy

Chưa thử API thương mại có 428. Chưa thử If-Unmodified-Since, PATCH, DELETE có điều kiện. Chưa thử server trả 2xx cho thay đổi đã áp dụng như RFC cho phép. Chưa thử ETag yếu do nén động, cache trung gian, HTTP/2. Hàm update_with_retry chỉ chạy trên API lab.

Chạy lại với API thật

Chọn một tài nguyên thử, không phải dữ liệu đang dùng. Chạy lại bảy phép thử trong bảng kết quả, so mã và ETag. Đặc biệt kiểm GET có trả ETag mạnh không, và 412 có trả ETag hiện hành không. Hai điểm này quyết định cách viết hàm cập nhật.

Proxy và cache trung gian

Proxy chuyển tiếp không đổi If-Match. Proxy có cache thì có thể trả GET từ bản lưu, kèm ETag cũ, khiến PUT sau nhận 412 liên tục. Header no-cache trên GET của lab là một cách phòng. Khi cần IP tại Việt Nam để gọi API trong nước, anh em có thể mua proxy tại trang chủ ProxyVN. Vai trò của proxy có ở bài Web Scraping proxy là gì, cách ghi chuỗi cấu hình có ở bài định dạng proxy.

Tài liệu tham khảo nhanh

Trang MDN về mã 428 tóm tắt mã này ngắn gọn. Khi cần quy tắc chính xác, đọc RFC 6585 cho 428 và RFC 9110 cho If-Match.

HTTP 428 Precondition Required: câu hỏi thường gặp

Các câu dưới đây gom những điểm hay bị hỏi.

428 có phải lỗi proxy không?

Không. 428 do ứng dụng phía server quyết định dựa trên header request. Đổi proxy không làm thay đổi kết quả.

Gửi If-Match: * có được không?

Qua được 428, nhưng không bảo vệ khỏi ghi đè. Lab nhận 200 với dấu sao dù tài nguyên đã đổi nhiều lần.

428 khác 412 thế nào?

428 là thiếu điều kiện. 412 là có điều kiện nhưng không thỏa. Sửa mã cho 428, đọc lại rồi thử lại cho 412.

Vì sao If-Match đúng vẫn nhận 412?

Có thể ETag yếu, thiếu ngoặc kép, hoặc tài nguyên vừa bị bên khác sửa. Lab có đủ ba ca này.

Có nên tự thử lại khi gặp 428?

Không. Thử lại không có If-Match chỉ nhận thêm 428. Sửa mã để luôn gửi điều kiện.

Cache có lưu được 428 không?

Theo RFC 6585, phản hồi 428 không được cache lưu lại.

httpx có xử lý 428 khác requests không?

Không trong lab. Cả hai trả mã, không tự thêm header. httpx đánh dấu is_client_error True.

HTTP 428 Precondition Required và những điều cần nhớ

HTTP 428 Precondition Required nghĩa là server đòi client chứng minh mình đang sửa bản mới nhất. Lấy ETag từ GET, gửi nguyên chuỗi trong If-Match, xử lý 412 bằng đọc lại và áp thay đổi lên bản mới, và đừng dùng dấu sao để né. Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam khuyên anh em chạy lại bảy phép thử trước khi bật pipeline ghi có HTTP 428 Precondition Required.

TIN TỨC LIÊN QUAN