如何用Ruby正则表达式捕获HTTP响应的所有Header名与值?
Ruby正则捕获所有HTTP响应Header的解决方案
你的问题出在重复捕获组的行为:当命名捕获组被包裹在(?:...)*这类重复结构里时,Ruby的正则引擎会在每次重复时覆盖捕获组的值,最终只保留最后一次匹配的结果。要获取所有Header,需要调整解析逻辑,分步骤提取或使用scan来捕获所有键值对。
方法一:拆分解析流程
先分离状态行、Header文本块和响应体,再对Header块逐个解析:
response = <<~RESPONSE HTTP/1.1 200 No Content Date: Mon, 19 Jul 2004 16:18:20 GMT Server: Apache Last-Modified: Sat, 10 Jul 2004 17:29:19 GMT ETag: "1d0325-2470-40f0276f" Accept-Ranges: bytes Content-Length: 9328 Connection: close Content-Type: text/html <HTML> <HEAD> </HEAD> <BODY> </BODY> </HTML> RESPONSE # 第一步:匹配状态行、Header文本块、响应体 if full_match = response.match(/^(?<statusline>HTTP\/(?<protocolversion>\d\.\d) (?<statuscode>\d+) (?<reasonphrase>[^\r\n]+))\r?\n(?<headers_text>(?:[^\r\n]+:\s*[^\r\n]*\r?\n)*)\r?\n(?<body>[\s\S]*)/m) # 提取状态行相关字段 status_data = { line: full_match[:statusline], protocol_version: full_match[:protocolversion], code: full_match[:statuscode], reason: full_match[:reasonphrase] } # 第二步:扫描Header文本块,捕获所有键值对 headers = {} full_match[:headers_text].scan(/(?<headername>[\w-]+):\s*(?<headervalue>[^\r\n]*)/) do |name, value| headers[name] = value.strip end body = full_match[:body] # 验证结果 puts "状态信息:" status_data.each { |k, v| puts " #{k}: #{v}" } puts "\n所有Header:" headers.each { |k, v| puts " #{k}: #{v}" } puts "\n响应体预览:\n#{body[0..50]}..." end
方法二:直接全局扫描所有Header
如果不需要先分离状态行,也可以直接用scan匹配整个响应中的所有Header行:
# 匹配所有Header行(跳过状态行) headers = {} response.scan(/^(?!HTTP\/)(?<headername>[\w-]+):\s*(?<headervalue>[^\r\n]*)/) do |name, value| headers[name] = value.strip end # 单独匹配状态行 status_match = response.match(/^(?<statusline>HTTP\/(?<protocolversion>\d\.\d) (?<statuscode>\d+) (?<reasonphrase>[^\r\n]+))/)
注意事项
- 上述方案未处理多行折叠Header(即值跨多行,以空格/制表符开头的情况),如果需要支持这种场景,需要额外处理换行后的内容。
- Ruby的
scan方法会遍历所有匹配项,是批量捕获重复结构的最优方式,比依赖单次匹配的重复捕获组更可靠。
内容的提问来源于stack exchange,提问作者l4t3b0
相关产品推荐
相关产品推荐

