如何使用netcat接收含多文件的HTTP响应并保存至磁盘?
嘿,这个需求我刚好折腾过,咱们一步步来搞定它!
核心思路
HTTP的multipart响应和tgz包不一样,它是用边界分隔符把每个文件拆分开的,每个文件还带着自己的HTTP头(比如包含文件名的Content-Disposition)。所以我们的步骤是:
- 从响应头部提取multipart的边界值
- 遍历响应内容,按边界拆分每个文件部分
- 从每个部分的头里提取文件名,然后把内容写入对应文件
方案1:用Awk处理文本文件场景
如果你要接收的都是文本类文件(比如txt、csv),用Awk脚本就能搞定,直接把命令链写成这样:
nc localhost 5000 | awk ' BEGIN { boundary = ""; in_header = 1; in_body = 0; filename = ""; file_handle = "" } # 第一步:从Content-Type头里提取边界 /^Content-Type: multipart/ { split($0, parts, /boundary=/) boundary = parts[2] gsub(/"/, "", boundary) # 去掉边界值可能带的引号 } # 遇到边界,关闭上一个文件(如果有的话),准备处理新文件 $0 ~ "--" boundary { if (file_handle != "") { close(file_handle) file_handle = "" } in_header = 1 in_body = 0 filename = "" next } # 从Content-Disposition头里提取文件名 in_header && /^Content-Disposition:/ { split($0, parts, /filename=/) filename = parts[2] gsub(/[";]/, "", filename) # 去掉文件名里的引号和分号 if (filename != "") { file_handle = filename printf "" > file_handle # 创建空文件 in_header = 0 in_body = 1 } next } # 空行是头部和正文的分隔符,跳过头部进入正文写入阶段 in_header && /^$/ { in_header = 0 if (filename != "") { in_body = 1 } next } # 把正文内容写入文件,直到遇到下一个边界 in_body && $0 !~ "--" boundary { print > file_handle } # 遇到结束边界(--boundary--),关闭文件并退出 $0 ~ "--" boundary "--" { if (file_handle != "") { close(file_handle) } exit } '
方案2:用Perl处理二进制文件场景
如果要接收图片、压缩包这类二进制文件,Awk可能会因为文本处理的特性搞乱二进制数据,这时候用Perl更靠谱,它能直接处理二进制流:
nc localhost 5000 | perl -e ' my $boundary = ""; my $in_header = 1; my $in_body = 0; my $filename = ""; my $fh; while (<>) { # 提取边界并加上开头的-- if (/^Content-Type: multipart\/.*boundary=(.*)$/) { $boundary = $1; $boundary =~ s/["]//g; $boundary = "--" . $boundary; } # 遇到边界,关闭上一个文件 if (/^$boundary/) { if ($fh) { close $fh; undef $fh; } $in_header = 1; $in_body = 0; $filename = ""; next; } # 提取文件名并打开文件(二进制模式) if ($in_header && /^Content-Disposition:.*filename=(.*)$/) { $filename = $1; $filename =~ s/[";]//g; if ($filename ne "") { open $fh, ">", $filename or die "Can't open $filename: $!"; binmode $fh; # 关键:启用二进制模式,避免换行符转换 $in_header = 0; $in_body = 1; } next; } # 跳过头部结束的空行 if ($in_header && /^$/) { $in_header = 0; next; } # 写入文件内容 if ($in_body && !/^$boundary/) { print $fh $_; } # 处理结束标记,退出脚本 if (/^$boundary--$/) { close $fh if $fh; exit; } } '
补充:关于tgz的情况
你提到的tgz方案确实更简单——如果服务器返回的是一个tgz压缩包,直接用nc localhost 5000 | tar xzvf -就能自动解压所有文件到当前目录。但这个只适用于响应是单一tgz包的情况,而如果是HTTP multipart格式的多文件响应,就得用上面的multipart解析脚本了。
内容的提问来源于stack exchange,提问作者user7898461
相关产品推荐
相关产品推荐

