如何用httr提取API返回的application/xop+xml格式中的ZIP附件?
问题背景
向API发送POST请求后,返回multipart/related; type="application/xop+xml"格式的响应,其中包含一个名为tmp12345.zip的附件,但直接用writeBin保存整个响应内容无法打开ZIP文件。
核心解决方案
响应是多部分复合格式,必须根据响应头中的boundary值拆分内容,定位到对应附件的二进制块后单独保存,具体步骤如下:
1. 明确响应结构
响应头中的boundary是拆分多部分内容的关键标记(本例中为uuid:0ca94e9c-b817-4e87-9628-656cdd58be68),每一部分以--{boundary}开头,最终以--{boundary}--结尾。目标附件块包含Content-Disposition: attachment;name="tmp12345.zip"标识。
2. 具体实现(Python示例)
import requests # 替换为你的API请求参数(已完成认证) response = requests.post("https://your-api-endpoint", auth=("username", "password"), data=your_request_body) # 从响应头提取boundary content_type_header = response.headers["Content-Type"] boundary = content_type_header.split('boundary="')[1].split('"')[0] part_delimiter = f"--{boundary}".encode("utf-8") end_delimiter = f"--{boundary}--".encode("utf-8") # 拆分响应的二进制内容 response_parts = response.content.split(part_delimiter) # 遍历查找目标附件 for part in response_parts: if b'Content-Disposition: attachment;name="tmp12345.zip"' in part: # 分离块头部和二进制内容(空行分隔) header_split_pos = part.find(b"\r\n\r\n") if header_split_pos != -1: zip_binary = part[header_split_pos + 4:] # 移除结尾的结束分隔符 if zip_binary.endswith(end_delimiter): zip_binary = zip_binary[:-len(end_delimiter)] # 保存ZIP文件 with open("extracted.zip", "wb") as zip_file: zip_file.write(zip_binary) break
3. R语言实现示例
library(httr) # 发送认证后的POST请求 api_response <- POST( url = "https://your-api-endpoint", authenticate("your-username", "your-password"), body = your_request_body ) # 提取boundary content_type <- headers(api_response)$`Content-Type` boundary <- sub('.*boundary="([^"]+)".*', "\\1", content_type) delimiter <- paste0("--", boundary) raw_content <- content(api_response, "raw") # 拆分内容并定位附件 content_str <- rawToChar(raw_content) parts <- strsplit(content_str, delimiter)[[1]] for (part in parts) { if (grepl('Content-Disposition: attachment;name="tmp12345.zip"', part)) { # 找到头部结束的空行位置 header_end <- regexpr("\r\n\r\n", part)[1] if (header_end != -1) { # 计算二进制内容在原始raw数据中的起始位置 raw_start <- header_end + 4 # 提取并保存二进制数据 zip_raw <- raw_content[raw_start:(length(raw_content) - nchar(delimiter) - 2)] writeBin(zip_raw, "extracted.zip") break } } }
关键注意事项
- 必须使用原始二进制内容处理,避免将响应转换为文本后再转回二进制,防止编码破坏ZIP结构。
- 拆分时要严格匹配
boundary的格式,注意前后的--标记。
内容的提问来源于stack exchange,提问作者fsumathguy
相关产品推荐
相关产品推荐

