我需要从 http-trafic 中提取上传。怎么可能这样做?首先,请求方法将是 POST。其次,会有一个 Content-Type 头域。我不想提取公式数据,而是像邮件附件一样上传。
3 回答
内容类型符合规范 multipart/form-data
。
这是一种特殊的内容类型,可以在一个大请求中可视化为多个子请求。这些子请求中的每一个(一个表单数据元素)都有自己的一组标题。实际数据的内容类型在那里。
这是一个使用 1 个普通字段和 1 个文件字段的示例(在 HTML 术语中,使用 时<input name="textfield"><input type="file" name="filefield">
):
Content-Type: multipart/form-data;boundary=SOME_BOUNDARY
--SOME_BOUNDARY
content-disposition: form-data;name="textfield"
content-type: text/plain;charset=UTF-8
value of textfield here
--SOME_BOUNDARY
content-disposition: form-data;name="filefield";filename="some.ext"
content-type: application/octet-stream
binary file content here
--SOME_BOUNDARY--
至于解析和提取这些数据,几乎每种编程语言都有内置/第三方 API。由于您没有说明您使用的是哪一个,因此不可能给出有针对性的答案。例如,在 Java 的情况下,可以是第三方库 Apache Commons FileUpload,或者当您使用 API 提供的request.getPart()
方法 Servlet 3.0 时。
如果(我绝不是说这是正确的方法)您只想从字节数组中保存数据,您应该查看如何读取 POST 正文: Reading POST body with bottle.py Reading the data and then创建一个新文件应该可以解决问题。
基于@BalusC 的解决方案,我为.NET 的内置WebClient 类做了一个小扩展方法,它不支持开箱即用的Multipart 上传。
用法
只需混合字符串值和文件(用#括起来)
public void UploadMultipart()
{
var fileName = "/some/existing/file.ext";
using (var client = new WebClient())
{
var values = new NameValueCollection();
values.Add("id", Guid.NewGuid().ToString());
values.Add("name", Path.GetFileNameWithoutExtension(fileName));
values.Add("file", $"#{fileName}#");
var result = client.UploadMultipart(address, method, values);
var content = client.Encoding.GetString(result);
}
}
扩展方法
public static byte[] UploadMultipart(this WebClient client,
string address, string method, NameValueCollection values)
{
string boundary = DateTime.Now.Ticks.ToString("x");
client.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
var sb = new StringBuilder()
.AppendLine();
foreach (var key in values.AllKeys)
{
var contentDispositon = $"form-data;name=\"{key}\"";
var contentType = $"text/plain;charset={client.Encoding.WebName}";
var value = values[key];
if (value.StartsWith("#") && value.EndsWith("#"))
{
// if a value is enclosed in hashes we expect this to be a path to a file
// file=#/path/to/file.ext#
var fileName = value.Trim('#');
var file = File.ReadAllBytes(fileName);
value = client.Encoding.GetString(file);
contentType = "application/octet-stream";
contentDispositon = $"form-data;name=\"{key}\"filename=\"{Path.GetFileName(fileName)}\"";
}
sb.AppendLine($"--{boundary}")
.AppendLine($"Content-Disposition: {contentDispositon}")
.AppendLine($"Content-Type: {contentType}")
.AppendLine()
.AppendLine(value);
}
sb.AppendLine($"--{boundary}--");
var data = client.Encoding.GetBytes(sb.ToString());
return client.UploadData(address, method, data);
}