HTTP Structured Fields parser: AST đúng kiểu, không split tay
HTTP Structured Fields parser là bộ đọc header theo chuẩn RFC 9651, biến chuỗi như u=5, i hay sig1=("@method");created=1 thành cây dữ liệu có kiểu rõ ràng: số nguyên, chuỗi, token, boolean, danh sách và tham số. Cách quen tay là tách chuỗi bằng dấu phẩy và dấu bằng, chạy được với ví dụ đơn giản rồi hỏng khi giá trị có dấu phẩy nằm trong ngoặc kép. ProxyVN chạy 20 header fixture qua hai thư viện Python thật và qua cách tách thủ công, rồi đặt ba kết quả cạnh nhau.
HTTP Structured Fields parser: mục tiêu và phạm vi không lặp
Phần này chốt bài toán, đầu ra và những gì bài không bàn.
Bài toán cần giải
Một công cụ giám sát đọc header Cache-Status từ response đi qua proxy để đếm tỷ lệ cache hit. Mã tách chuỗi bằng dấu phẩy rồi tìm chữ hit. Một ngày CDN đổi tên thành viên thành chuỗi có ngoặc kép và dấu phẩy, số liệu nhảy lung tung. Không có lỗi nào được báo, chỉ có con số sai.
Đầu ra nghiệm thu
Đầu ra là bộ header fixture có chuỗi trích dẫn, tham số, boolean, byte sequence, ngày và display string, kèm bảng AST do parser chuẩn sinh ra. Mỗi fixture có ba cột: kết quả của http_sf, kết quả của http_sfv và kết quả của cách tách thủ công. Ca lỗi ghi thông báo lỗi thay vì giá trị.
Ranh giới với parse HTML và JSON
Bài không bàn parse HTML hay JSON. Structured Fields là một cú pháp riêng cho giá trị header, có kiểu dữ liệu và luật lỗi riêng. Nó không phải JSON trong header. Một bộ đọc JSON không đọc được u=5, i, và một bộ đọc Structured Fields không đọc được JSON.
Ranh giới với từng header cụ thể
Các bài khác trên blog có thể bàn về Priority, Cache-Status hay chữ ký HTTP. Bài này không giải thích ý nghĩa của từng header. Nó chỉ dùng các header đó làm fixture để kiểm bộ đọc. Ý nghĩa thì đọc ở đặc tả của từng header.
Giới hạn của lab
Lab chỉ chạy offline, không gửi request nào. Thứ thật là hai thư viện http_sf 1.5.0 và http_sfv 0.9.9 cài từ PyPI, chạy trên Python 3.12.10 Windows. Hàm tách thủ công do lab viết, mô phỏng cách làm phổ biến. Không có thư viện thứ ba bằng ngôn ngữ khác được so.
Ai nên đọc
Người viết công cụ giám sát hay crawler đọc header từ response. Người viết proxy hoặc middleware cần đọc và ghi lại header kiểu mới. Người đang có hàm split(',') trong mã và muốn biết khi nào nó sai.
Parse structured dictionary/list/item đúng kiểu thay vì split dấu phẩy thủ công với HTTP Structured Fields parser
Phần này giải thích vì sao tách chuỗi thủ công không đủ.
Chuẩn định nghĩa kiểu
RFC 9651 định nghĩa ba kiểu ở mức cao nhất: List, Dictionary và Item. Bên trong có các kiểu giá trị: Integer, Decimal, String, Token, Byte Sequence, Boolean, Date và Display String. Mỗi thành viên có thể mang tham số. List và Dictionary có thể chứa Inner List.
Dấu phẩy có nhiều vai
Trong Structured Fields, dấu phẩy ngăn cách thành viên của List hoặc Dictionary. Nhưng dấu phẩy cũng có thể nằm trong một String có ngoặc kép. Tách chuỗi theo mọi dấu phẩy là bỏ qua ngoặc kép. Chuỗi a="x, y" bị tách thành hai mảnh vô nghĩa.
Dấu chấm phẩy và dấu bằng
Dấu chấm phẩy mở đầu tham số của một thành viên, dấu bằng gán giá trị cho khóa hay tham số. Một thành viên như OriginCache; hit; ttl=1100 có giá trị là token OriginCache, tham số hit là true và ttl là 1100. Cách tách thủ công gộp cả chuỗi trước dấu bằng thành khóa.
Kiểu không suy được từ chuỗi
Chuỗi 5, chuỗi "5" có ngoặc kép và ?1 là ba kiểu khác nhau: Integer, String và Boolean. Tách thủ công trả về chuỗi ký tự cho mọi thứ, người dùng phải tự đoán. Parser chuẩn trả về đúng kiểu, nên mã phía sau không cần đoán.
Luật lỗi nghiêm
RFC 9651 nói khi parse thất bại, cả giá trị header phải bị bỏ qua, hoặc cả thông điệp bị coi là hỏng. Đặc tả của từng header không được nới luật này. Tách thủ công không bao giờ thất bại, nó luôn trả về một thứ gì đó, kể cả khi header sai.
If parsing fails, either the entire field value MUST be ignored or alternatively the complete HTTP message MUST be treated as malformed. (RFC 9651, mục 4.2)
Header chưa phải Structured Fields
Không phải header nào cũng dùng cú pháp này. Accept, Cache-Control, Set-Cookie ra đời trước và có ngữ pháp riêng. Chỉ header nào đặc tả nói là Structured Field mới được parse theo RFC 9651. Bảng 1 của RFC 9651 liệt kê các header đã có từ trước được gán kiểu, như Priority, Cache-Status, Proxy-Status, CDN-Cache-Control.
Phiên bản mới thêm kiểu
RFC 9651 thay RFC 8941 và thêm hai kiểu: Date bắt đầu bằng ký tự @, và Display String bắt đầu bằng %" cho phép chữ Unicode qua mã hóa phần trăm. Bộ đọc viết theo RFC 8941 sẽ từ chối hai kiểu này. Fixture F07 và F08 của lab kiểm đúng điểm này.
Vì sao cần cây dữ liệu
Kết quả parse là một cây: Dictionary chứa các cặp khóa và thành viên, mỗi thành viên là giá trị cộng tham số. Bài gọi cây này là AST. Mã phía sau làm việc trên AST, không làm việc trên chuỗi. Ghi lại header cũng đi từ AST qua bộ ghi chuẩn.
Chọn kiểu dictionary, list hay item theo đặc tả header trong HTTP Structured Fields parser
Parser phải được báo trước header là kiểu nào. Phần này giải thích vì sao.
Cùng chuỗi, ba kiểu khác nhau
Chuỗi a, b parse như List là hai token. Parse như Dictionary là hai khóa có giá trị true. Parse như Item thì lỗi vì có ký tự thừa sau token đầu. Parser không tự đoán được, kiểu phải lấy từ đặc tả của header.
Bảng kiểu của các header trong lab

Chọn kiểu theo đặc tả
Header |
Kiểu |
Nguồn |
|---|---|---|
Priority |
Dictionary |
RFC 9218, RFC 9651 bảng 1 |
Cache-Status |
List |
RFC 9211, RFC 9651 bảng 1 |
Proxy-Status |
List |
RFC 9209, RFC 9651 bảng 1 |
Signature-Input |
Dictionary |
RFC 9421 |
Sec-CH-UA |
List |
Client Hints |
Accept, Cache-Control |
Không phải Structured Field |
Ngữ pháp riêng trong RFC 9110, RFC 9111 |
Gọi http_sf theo kiểu
Thư viện http_sf nhận tham số tltype là dictionary, list hoặc item. Hàm trả về kiểu Python: dict cho Dictionary, list cho List, và tuple gồm giá trị với dict tham số cho mỗi thành viên. Đây là cách lab gọi cho mọi fixture.
import http_sf
v = http_sf.parse(b'u=5, i', tltype="dictionary")
# {'u': (5, {}), 'i': (True, {})}
v = http_sf.parse(b'OriginCache; hit; ttl=1100', tltype="list")
# [(Token('OriginCache'), {'hit': True, 'ttl': 1100})]
Gọi theo tên header
http_sf còn nhận tham số name. Lab gọi với name là priority và cache-status, thư viện tự chọn Dictionary và List. Với một tên chưa có trong bảng của thư viện, x-chua-dang-ky, thư viện ném KeyError với thông báo unrecognised top-level type. Không đoán bừa là hành vi đúng.
Bảng retrofit của thư viện
Lab gọi http_sf với name là accept và cache-control. Thư viện vẫn parse được, Accept thành List có tham số q, Cache-Control thành Dictionary. Đây là bảng ánh xạ riêng của thư viện, không phải định nghĩa của RFC 9651. Hai header này vẫn có ngữ pháp riêng, có giá trị hợp lệ theo RFC 9110 mà bộ đọc Structured Fields sẽ từ chối.
Gọi http_sfv theo lớp
http_sfv dùng ba lớp Dictionary, List và Item. Tạo đối tượng đúng lớp rồi gọi parse với bytes. Thành viên có thuộc tính value và params. Lab dùng thư viện này làm đối chứng thứ hai, và in lại kết quả bằng bộ ghi của nó.
import http_sfv
d = http_sfv.Dictionary()
d.parse(b'a="x, y", b=?0, c')
for k, m in d.items():
print(k, repr(m.value), dict(m.params))
Khi đặc tả không nói kiểu
Header tự đặt của dự án thường không có đặc tả. Lúc đó đội phải tự viết một dòng đặc tả: tên header, kiểu cao nhất, các khóa và kiểu giá trị. Một dòng như vậy giúp mọi dịch vụ đọc cùng một cách, thay vì mỗi nơi tách chuỗi một kiểu.
Kiểu sai cho ra lỗi đúng
Lab parse cùng chuỗi a, b, ở kiểu List và nhận lỗi Trailing comma. Nếu dùng nhầm kiểu Item cho một header List, lỗi sẽ xuất hiện ngay ở ca có hai thành viên. Lỗi sớm như vậy tốt hơn một giá trị sai im lặng.
Parse quoted string, boolean, parameter và khóa với HTTP Structured Fields parser
Phần này đi qua từng kiểu giá trị bằng fixture thật.
Chuỗi trích dẫn
F05 là k="he said \"hi, there\"". http_sf trả String he said "hi, there", với ngoặc kép bên trong đã được bỏ dấu gạch chéo. Cách tách thủ công cắt chuỗi ở dấu phẩy, ra một khóa k với giá trị bắt đầu bằng ngoặc kép và một khóa rác there.
Chuỗi chỉ nhận ASCII
F20 là chuỗi "có dấu". Cả hai thư viện đều từ chối, http_sf báo String contains disallowed character at position 2. String trong Structured Fields chỉ nhận ký tự ASCII in được. Chữ tiếng Việt phải dùng Display String, như F08.
Display String
F08 là title=%"xin ch%c3%a0o". http_sf trả kiểu DisplayString với giá trị xin chào. Byte UTF-8 của chữ à được mã hóa phần trăm là %c3%a0. Cách tách thủ công giữ nguyên cả ký tự phần trăm và ngoặc kép.
Boolean
F04 có b=?0 và c không có giá trị. http_sf trả b là false và c là true. Một khóa không có dấu bằng là boolean true theo chuẩn. Cách tách thủ công trả ?0 dạng chuỗi, mã phía sau dễ coi chuỗi khác rỗng là true và hiểu ngược ý.
Byte Sequence
F06 là d=:cHJldGVuZCB0aGlzIGlzIGJpbmFyeQ==:. Hai dấu hai chấm bao một chuỗi base64. http_sf trả bytes đã giải mã, lab in lại dạng base64 để so. Cách tách thủ công giữ cả hai dấu hai chấm, nên giải mã base64 trực tiếp sẽ lỗi.
Ngày
F07 là @1659578233, một Date của RFC 9651. http_sf trả datetime 2022-08-04T01:57:13+00:00. http_sfv 0.9.9 parse được và ghi lại đúng chuỗi. Cách tách thủ công trả một khóa tên @1659578233 với giá trị true.
Tham số
F02 là Cache-Status hai thành viên. Thành viên đầu là token OriginCache với tham số hit true và ttl 1100. Thành viên sau là String CDN Company Here với tham số fwd là token uri-miss. Cách tách thủ công tạo hai khóa dài vô nghĩa như OriginCache; hit; ttl.
Inner List
F03 giống Signature-Input: sig1=("@method" "@authority" "content-digest");created=1618884473;keyid="test-key". http_sf trả cho sig1 một danh sách ba String, kèm tham số created là số nguyên và keyid là chuỗi. Cách tách thủ công trả toàn bộ phần sau dấu bằng như một chuỗi.
Khóa viết hoa
F11 là A=1. Cả hai thư viện từ chối, http_sf báo Key cannot begin with an uppercase character. Khóa trong Structured Fields chỉ có chữ thường, số và vài ký tự. Cách tách thủ công nhận A như khóa hợp lệ, nên hai dịch vụ có thể hiểu cùng header theo hai cách.
Khóa trùng
F12 là a=1, a=2. Cả hai thư viện trả a bằng 2, đúng thuật toán của RFC 9651: gặp khóa đã có thì ghi đè. Cách tách thủ công cũng ra 2 trong ca này, nhưng chỉ vì nó ghi dict theo thứ tự. Hai cách cho cùng kết quả vì tình cờ, không vì cùng luật.
Kiểm fixture có dấu phẩy nằm trong giá trị với HTTP Structured Fields parser
Đây là phần chính của lab: ca có dấu phẩy và ca biên.
Dấu phẩy trong chuỗi
F04 là a="x, y", b=?0, c. http_sf trả ba khóa: a là chuỗi x, y, b là false, c là true. Cách tách thủ công trả bốn khóa: a mang giá trị "x còn dính ngoặc kép mở, thêm một khóa rác là y" dính ngoặc kép đóng, rồi b là ?0 và c là true. Số khóa sai, giá trị sai, không có lỗi.
Dấu phẩy trong Sec-CH-UA
F14 là "Not?A_Brand";v="24", "Chromium";v="152", giá trị thật của trình duyệt Chromium 152. http_sf trả List hai String, mỗi cái có tham số v. Cách tách thủ công tình cờ không gặp dấu phẩy trong chuỗi ở ca này, nhưng tạo khóa chứa ngoặc kép và dấu chấm phẩy.
Tab giữa thành viên
F17 là a=1, ký tự tab, b=2. Cả hai thư viện đọc được hai khóa số nguyên. RFC 9651 cho phép tab ở chỗ này vì một số bộ gộp header dùng tab. Cách tách thủ công cũng xử lý được nhờ strip, nhưng giá trị vẫn là chuỗi.
Dấu phẩy thừa ở cuối
F13 là a, b, với dấu phẩy cuối. Cả hai thư viện từ chối với Trailing comma at end of list. Cách tách thủ công bỏ qua mảnh rỗng và trả hai khóa. Chuẩn yêu cầu bỏ cả header, nên công cụ tách thủ công đang dùng một header mà chuẩn bảo phải bỏ.
Header rỗng
F16 là List rỗng. Theo thuật toán parse List của RFC 9651, chuỗi rỗng cho ra danh sách rỗng. http_sf trả [] đúng như vậy. http_sfv 0.9.9 ném ValueError. Đây là chỗ hai thư viện bất đồng, và http_sfv đang lệch chuẩn trong lab.
Item rỗng
F15 là Item rỗng. Cả hai thư viện từ chối, http_sf báo Empty item at position 0. Item bắt buộc có giá trị. Cách tách thủ công trả dict rỗng, mã phía sau sẽ không biết header có mặt mà rỗng hay không có mặt.
Số quá dài
F09 là v=1.2345, phần thập phân bốn chữ số. F10 là số nguyên 16 chữ số. Cả hai thư viện từ chối cả hai ca. Decimal chỉ nhận tối đa ba chữ số thập phân, Integer tối đa 15 chữ số. Cách tách thủ công trả chuỗi, và float của Python đọc được cả hai.
Gộp nhiều dòng header
RFC 9651 yêu cầu gộp mọi dòng của cùng header bằng dấu phẩy trước khi parse. Hai dòng Priority là u=1 và i gộp thành u=1, i, parse ra u bằng 1 và i là true. Lab cũng parse "foo, bar" như một String, đúng điều RFC cảnh báo khi một chuỗi bị tách qua hai dòng rồi gộp lại.
Bảng kết quả rút gọn

Bảng ba cột kết quả
Fixture |
http_sf 1.5.0 |
http_sfv 0.9.9 |
Tách thủ công |
|---|---|---|---|
F04 a="x, y", b=?0, c |
3 khóa đúng kiểu |
3 khóa |
4 khóa, sai |
F05 chuỗi có \" và dấu phẩy |
1 String đúng |
đúng |
2 khóa, sai |
F07 Date @1659578233 |
datetime |
đúng |
khóa rác |
F08 Display String |
xin chào |
đúng |
giữ mã % |
F09 v=1.2345 |
lỗi |
lỗi |
chuỗi |
F11 A=1 |
lỗi |
lỗi |
khóa A |
F13 dấu phẩy cuối |
lỗi |
lỗi |
2 khóa |
F16 List rỗng |
[] |
lỗi |
{} |
F20 "có dấu" |
lỗi |
lỗi |
khóa rác |
Tách thủ công sai ở đâu
Trên 20 fixture, cách tách thủ công cho kết quả có thể dùng được ở F01, F12 và F17, nơi mọi giá trị là số hoặc boolean đơn giản. Ở các ca còn lại, nó hoặc tạo khóa rác, hoặc giữ ký tự cú pháp trong giá trị, hoặc nhận header mà chuẩn bảo phải bỏ.
Xuất AST và lỗi parse thay vì split chuỗi thủ công trong HTTP Structured Fields parser
Phần này nói cách đưa AST vào log và vào mã xử lý.
Ghi AST có kiểu

AST và lỗi có vị trí
Lab chuyển kết quả của http_sf sang JSON có nhãn kiểu: int, dec, str, token, bool, bytes, date, display. Một thành viên có tham số ghi thành v và params. Định dạng này lưu được vào log, so được giữa hai lần chạy và đọc được bằng mắt.
def j(v):
if isinstance(v, bool): return {"bool": v}
if isinstance(v, int): return {"int": v}
if isinstance(v, decimal.Decimal): return {"dec": str(v)}
if isinstance(v, http_sf.Token): return {"token": str(v)}
if isinstance(v, http_sf.DisplayString): return {"display": str(v)}
if isinstance(v, str): return {"str": v}
if isinstance(v, bytes): return {"bytes": base64.b64encode(v).decode()}
if isinstance(v, datetime.datetime): return {"date": v.isoformat()}
if isinstance(v, tuple):
base = j(v[0])
return {"v": base, "params": {k: j(x) for k, x in v[1].items()}} if v[1] else base
if isinstance(v, list): return [j(x) for x in v]
if isinstance(v, dict): return {k: j(x) for k, x in v.items()}
Thứ tự kiểm bool trước int
Trong Python, True là số nguyên. Hàm j kiểm bool trước int, nếu không boolean true sẽ thành int 1 trong log. Đây là cùng một cái bẫy với khi đọc tham số i của Priority.
Ghi lỗi có vị trí
Thông báo lỗi của http_sf có vị trí ký tự và khóa đang đọc, ví dụ Decimal fractional component too long at position 7 (in 'v'). Ghi nguyên thông báo này vào log. Thông báo lỗi của http_sfv 0.9.9 thường rỗng, chỉ có tên ValueError, nên khó chẩn đoán hơn.
Bỏ cả header khi lỗi
Mã xử lý phải coi lỗi parse là header không có mặt, như RFC 9651 yêu cầu. Không giữ lại các khóa đã đọc được trước chỗ lỗi. Ghi một dòng log với tên header, giá trị gốc và lỗi, để người vận hành biết header nào đang bị bỏ.
Ghi lại header từ AST
Khi proxy hay middleware cần sửa header, parse sang AST, sửa AST, rồi ghi lại bằng bộ ghi của thư viện. Lab ghi lại a="x, y", b=?0,c thành a="x, y", b=?0, c, và v=1.50 thành v=1.5. Bộ ghi chuẩn hóa khoảng trắng và số, nên header ra luôn đúng cú pháp.
Chuẩn hóa làm đổi chuỗi
Vì bộ ghi chuẩn hóa, chuỗi header ra có thể khác chuỗi vào dù ý nghĩa giống nhau. Nếu header đó được ký, như Signature-Input, việc ghi lại có thể làm chữ ký không khớp. Với header được ký, proxy nên chuyển nguyên chuỗi, chỉ parse để đọc.
Đừng ghép chuỗi tay khi tạo header
Tạo header bằng f-string dễ quên ngoặc kép, quên bỏ ký tự đặc biệt hay ghi số sai định dạng. Tạo dict hoặc list rồi gọi http_sf.ser cho ra chuỗi đúng. Đây là phần ngược của việc không split tay khi đọc.
Đầu ra nghiệm thu HTTP Structured Fields parser: bộ header fixture có quote parameter và bảng AST parser chuẩn
Phần này gom đầu ra thành bản ghi có thể lưu.
Tệp đầu ra
Lab sinh result.json gồm phiên bản thư viện, 20 fixture, mỗi fixture có AST của http_sf, chuỗi ghi lại của http_sfv và kết quả tách thủ công. out.txt là bản in của cùng dữ liệu, kèm phần chọn kiểu theo tên header, phần gộp dòng và phần ghi lại.
Danh sách kiểm tra

Danh sách nghiệm thu
- Kiểu cao nhất của mỗi header lấy từ đặc tả, không đoán.
- Có fixture chuỗi trích dẫn chứa dấu phẩy và ngoặc kép.
- Có fixture Date và Display String của RFC 9651.
- Có fixture lỗi: khóa hoa, số quá dài, dấu phẩy cuối, chuỗi không ASCII.
- Có ca List rỗng và Item rỗng.
- Lỗi parse dẫn tới bỏ cả header, có log.
- Header tạo ra đi qua bộ ghi chuẩn.
Những gì lab chưa chạy
Chưa so với thư viện ở ngôn ngữ khác như Go, Rust hay JavaScript. Chưa chạy bộ test chính thức của cộng đồng Structured Fields. Chưa đo hiệu năng với header lớn. Chưa đọc header từ response thật qua mạng. Chưa thử header được ký đi qua proxy ghi lại.
Câu kết luận được phép viết
Câu được phép viết là: trên 20 fixture, http_sf 1.5.0 và http_sfv 0.9.9 cùng từ chối các ca sai cú pháp, bất đồng ở List rỗng, còn tách thủ công cho kết quả sai ở phần lớn fixture. Câu không được phép viết là: http_sfv sai chuẩn nói chung. Lab chỉ thấy một ca lệch.
Vận hành công cụ đọc header với HTTP Structured Fields parser
Phần này chuyển kết quả lab thành việc cần làm khi đọc header từ response thật.
Thay hàm split trong công cụ giám sát
Tìm mọi chỗ trong mã đọc Cache-Status, Proxy-Status, Priority hay Signature-Input bằng split. Thay bằng một hàm dùng chung gọi parser với đúng kiểu. Hàm trả AST hoặc None, kèm log khi lỗi. Công cụ giám sát trong bài toán đầu bài sẽ đếm đúng dù CDN đổi tên thành viên.
Khóa phiên bản thư viện
Ghi phiên bản parser vào tệp phụ thuộc của dự án. Lab cho thấy hai thư viện có thể bất đồng ở ca biên. Nâng phiên bản là một thay đổi cần chạy lại bộ fixture, không phải cập nhật thường lệ.
Proxy không nên sửa header lạ
Proxy chỉ chuyển tiếp không cần parse Structured Fields. RFC 9651 nói tầng trung gian không bắt buộc bỏ header parse lỗi trước khi chuyển. Proxy parse và ghi lại header nó không hiểu có thể đổi chuỗi và làm hỏng chữ ký. Giữ nguyên là lựa chọn an toàn.
Header gộp qua proxy
Một số proxy gộp nhiều dòng cùng tên thành một dòng có dấu phẩy. Với List và Dictionary, việc gộp đúng chuẩn. Với String bị tách qua hai dòng, kết quả không đoán được, như lab đã thấy với "foo, bar". Header tự đặt của dự án không nên dựa vào nhiều dòng.
Giới hạn kích thước
RFC 9651 nhắc rằng kích thước của hầu hết kiểu không có giới hạn, header cực lớn có thể là đường tấn công làm cạn tài nguyên. Công cụ đọc header nên đặt giới hạn độ dài trước khi parse, như nhiều máy chủ HTTP đã làm.
Mã hóa ngược Display String
Khi tạo header có chữ tiếng Việt, đưa chuỗi Python vào kiểu DisplayString rồi gọi bộ ghi, thư viện sẽ tự mã hóa phần trăm các byte UTF-8. Không tự gõ %c3%a0 bằng tay. Bên nhận cũng phải dùng parser hỗ trợ RFC 9651, nếu không header sẽ bị bỏ vì ký tự phần trăm không hợp lệ ở bộ đọc cũ.
So sánh kết quả giữa hai thư viện
Trong giai đoạn chuyển đổi, chạy cả hai parser trên cùng header thật trong một thời gian và ghi những ca kết quả khác nhau. Lab chỉ thấy một ca khác ở List rỗng, nhưng header thật có thể có ca biên khác. Danh sách ca khác nhau là đầu vào tốt để bổ sung fixture.
Không ghi AST thay cho chuỗi gốc
Log nên giữ cả chuỗi header gốc và AST. Chuỗi gốc là bằng chứng nguồn đã gửi gì, AST là cách công cụ đã hiểu. Khi có tranh cãi về số liệu, hai thứ đặt cạnh nhau trả lời nhanh lỗi nằm ở nguồn hay ở bộ đọc.
Ghi kiểu của header tự đặt vào tài liệu API
Nếu API của dự án trả header tự đặt, ghi kiểu Structured Fields của nó vào tài liệu API cùng ví dụ. Bên gọi API dùng parser chuẩn và không phải đoán. Đây cũng là cách RFC 9651 khuyến khích các đặc tả header mới làm.
Proxy ở đâu trong luồng
Parser là phần xử lý offline sau khi tải, không cần proxy. Proxy chỉ có vai trò ở tầng tải response từ nguồn. Khi cần IP tại Việt Nam cho phần tải, 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.
Đưa fixture vào test
Bộ 20 fixture chạy trong chưa tới một giây. Đặt nó trong test của dự án, kiểm hàm đọc header dùng chung. Thêm fixture mỗi khi gặp một giá trị header lạ trong log. Bộ fixture lớn dần là tài sản của đội.
HTTP Structured Fields parser: câu hỏi thường gặp
Các câu dưới đây gom những điểm hay bị hỏi.
Có thể split dấu phẩy nếu header đơn giản không?
Chỉ khi chắc mọi giá trị là số hoặc boolean. Trong lab, tách thủ công sai ngay khi có chuỗi trích dẫn chứa dấu phẩy.
Accept có phải Structured Field không?
Không. Accept có ngữ pháp riêng trong RFC 9110. http_sf parse được nhờ bảng ánh xạ riêng của thư viện, không phải theo RFC 9651.
Chữ tiếng Việt trong header thì sao?
String chỉ nhận ASCII. Dùng Display String của RFC 9651, ví dụ %"xin ch%c3%a0o".
Parse lỗi thì làm gì?
Bỏ cả header, coi như không có mặt, và ghi log. Không giữ phần đã đọc được.
Khóa trùng trong Dictionary thì sao?
Giá trị sau ghi đè giá trị trước. Lab parse a=1, a=2 ra a bằng 2.
Nên chọn http_sf hay http_sfv?
Trong lab, http_sf 1.5.0 đúng chuẩn ở ca List rỗng và có thông báo lỗi rõ hơn. Chạy bộ fixture với cả hai trước khi chọn.
Có cần proxy để parse header không?
Không. Parse chạy offline trên chuỗi đã có. Proxy chỉ liên quan tới việc tải response.
HTTP Structured Fields parser và những điều cần nhớ
HTTP Structured Fields parser biến giá trị header thành AST có kiểu và từ chối header sai cú pháp, điều cách tách dấu phẩy thủ công không làm được. Lab với 20 fixture cho thấy tách thủ công sai ở chuỗi trích dẫn, tham số, Date và Display String. 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ọn kiểu theo đặc tả và khóa phiên bản thư viện cho HTTP Structured Fields parser.