python解析http request字符串

如果通过抓包工具抓到一个raw http request,想要解析它,可以使用如下方法。

编写一个继承自python内置基类BaseHTTPRequestHandler的类,代码如下:

from BaseHTTPServer import BaseHTTPRequestHandler
from StringIO import StringIO

class HTTPRequest(BaseHTTPRequestHandler):
    def __init__(self, request_text):
        self.rfile = StringIO(request_text)
        self.raw_requestline = self.rfile.readline()
        self.error_code = self.error_message = None
        self.parse_request()

    def send_error(self, code, message):
        self.error_code = code
        self.error_message = message

然后通过这个类的实例就可以访问解析后的数据了

# Using this new class is really easy!

request = HTTPRequest(request_text)

print request.error_code       # None  (check this first)
print request.command          # "GET"
print request.path             # "/who/ken/trust.html"
print request.request_version  # "HTTP/1.1"
print len(request.headers)     # 3
print request.headers.keys()   # ['accept-charset', 'host', 'accept']
print request.headers['host']  # "cm.bell-labs.com"

要想知道HTTPRequest有哪些属性,可以查看python文档对“BaseHTTPServer.BaseHTTPRequestHandler”的说明。

欢迎扫描下方二维码关注我的微信公众号致新(zhixin991),那里有我的读书笔记,计算机科普和杂谈


<think>我们有一个需求:将接收到的payload报文解析为JSON字符串。根据引用[2]和引用[4]提供的信息,我们可以分步骤实现。 步骤1:获取原始payload数据 在服务端,我们通常通过读取HTTP请求体(body)来获取payload。引用[2]中提供了一个Java方法示例,使用`HttpServletRequest`对象来读取请求体: ```java private String getRequestPayload(HttpServletRequest req) { StringBuilder sb = new StringBuilder(); try (BufferedReader reader = req.getReader()) { char[] buff = new char[1024]; int len; while ((len = reader.read(buff)) != -1) { sb.append(buff, 0, len); } } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } ``` 这个方法返回的是整个请求体的字符串。如果请求的Content-Type是application/json,那么这个字符串就是JSON字符串。 步骤2:处理可能的二进制数据(如压缩数据) 引用[1]提到,如果payload中包含二进制数据(例如经过压缩的数据,可能包含null字符),则不能使用字符串函数(如strlen)来获取长度,因为null字符会被视为字符串的结束。在服务端,我们通过读取字节流并指定长度来避免截断。但是,在上面的方法中,我们使用字符流读取,实际上已经将整个请求体读取为一个字符串,包括其中的null字符(因为read方法读取的是字符,不会因为null而停止,但要注意字符编码)。如果payload是二进制数据,直接转换成字符串可能会损坏数据,因此需要特别注意。 然而,我们的目标是将payload解析为JSON字符串,这意味着payload应该是文本格式(JSON字符串)。如果payload是二进制格式(如gzip压缩后的数据),则需要先解压缩再解析。 步骤3:反序列化JSON字符串 得到JSON字符串后,我们可以使用JSON库将其解析为JSON对象(在Java中通常为`JsonObject`或自定义的POJO)。引用[4]展示了使用ArduinoJson库进行反序列化的示例,在Java中我们可以使用Jackson、Gson等库。 例如,使用Jackson库: ```java import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; // 假设我们获取到的payload字符串是jsonString String jsonString = getRequestPayload(request); ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonNode = objectMapper.readTree(jsonString); ``` 或者,如果我们有对应的POJO类,也可以直接反序列化为对象: ```java MyDataClass data = objectMapper.readValue(jsonString, MyDataClass.class); ``` 步骤4:处理特殊情况 如果payload是压缩过的(如gzip),那么我们需要先解压缩。但是,这通常会在HTTP头中指明(如Content-Encoding: gzip)。在服务端,如果请求头中有Content-Encoding且值为gzip,则需要先解压缩再解析。 在Java中,我们可以使用`GZIPInputStream`来解压缩: ```java private String getGzippedPayload(HttpServletRequest req) throws IOException { try (GZIPInputStream gzipInputStream = new GZIPInputStream(req.getInputStream()); BufferedReader reader = new BufferedReader(new InputStreamReader(gzipInputStream, StandardCharsets.UTF_8))) { StringBuilder sb = new StringBuilder(); char[] buffer = new char[1024]; int len; while ((len = reader.read(buffer)) != -1) { sb.append(buffer, 0, len); } return sb.toString(); } } ``` 然后,再对返回的字符串进行JSON解析。 总结步骤: 1. 检查请求头中的Content-Encoding,如果是gzip,则使用解压缩方法读取请求体。 2. 否则,使用普通方法读取请求体(如步骤1)。 3. 将读取到的字符串(JSON字符串)用JSON库解析。 注意:如果请求体是二进制格式(非文本),并且不是压缩的,那么它可能不是JSON格式,此时不能直接转换为字符串解析。通常,JSON payload是文本格式。 因此,解析payload为JSON字符串的关键是正确读取请求体,然后使用JSON库解析。 相关问题: 1. 如何正确处理gzip压缩的HTTP请求体? 2. 在Java中,常用的JSON解析库有哪些,它们之间有何区别? 3. 如果JSON字符串非常大,如何高效地解析? 4. 如何验证JSON字符串的合法性?</think>### 将Payload报文解析为JSON字符串的步骤 #### 1. **获取原始Payload数据** - 从HTTP请求体中读取原始字节流(避免使用字符串截断函数) - Java示例(Servlet环境): ```java public String getPayload(HttpServletRequest request) { try (InputStream inputStream = request.getInputStream()) { ByteArrayOutputStream result = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { result.write(buffer, 0, length); // 正确处理二进制数据 } return result.toString("UTF-8"); // 按需指定编码 } catch (IOException e) { throw new RuntimeException("Payload读取失败"); } } ``` *关键点:使用字节流避免`null`字符截断问题[^1]* #### 2. **处理特殊编码格式** - 若Payload是压缩数据(如gzip),需先解压: ```java public String decompress(byte[] compressed) { try (ByteArrayInputStream bis = new ByteArrayInputStream(compressed); GZIPInputStream gis = new GZIPInputStream(bis)) { return new String(gis.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException("解压失败"); } } ``` #### 3. **JSON反序列化** - **Java(Jackson库)**: ```java ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(payloadString); // 转为JSON树 ``` - **JavaScript(浏览器环境)**: ```javascript const jsonObj = JSON.parse(payloadString); ``` - **Python**: ```python import json data = json.loads(payload_bytes.decode('utf-8')) # 字节流转JSON ``` #### 4. **处理二进制Payload** - 当Payload包含二进制数据时(如图片/SMB协议): ```java // 提取二进制部分并Base64编码 String base64Data = Base64.getEncoder().encodeToString( payloadString.getBytes(StandardCharsets.ISO_8859_1) ); jsonNode.put("binaryData", base64Data); // 嵌入JSON ``` #### 5. **完整解析流程示例 ```java public JsonNode parsePayload(HttpServletRequest request) { // 1. 读取原始字节 byte[] rawPayload = request.getInputStream().readAllBytes(); // 2. 检查压缩标识(示例) if (request.getHeader("Content-Encoding").equals("gzip")) { rawPayload = decompress(rawPayload); } // 3. 转为JSON对象 return new ObjectMapper().readTree(new String(rawPayload, "UTF-8")); } ``` ### 关键注意事项 1. **字符编码**:明确指定编码(推荐UTF-8),避免乱码 2. **二进制处理**:对非文本数据使用Base64编码[^3] 3. **内存安全**:大文件Payload需使用流式解析(如Jackson的`JsonParser`) 4. **错误处理**:捕获`JsonParseException`等异常 5. **数据验证**:使用JSON Schema验证结构合法性 --- ### 相关问题 1. **当Payload包含混合文本和二进制数据时,如何设计高效的解析方案?** 2. **如何优化大体积JSON Payload(>100MB)的解析性能?** 3. **在微服务架构中,如何统一不同语言的Payload解析标准?** 4. **如何处理恶意构造的畸形JSON Payload带来的安全风险?** 5. **JSON和Protocol Buffers格式的Payload解析性能对比有何差异?**[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值