35

我需要从 http-trafic 中提取上传。怎么可能这样做?首先,请求方法将是 POST。其次,会有一个 Content-Type 头域。我不想提取公式数据,而是像邮件附件一样上传。

4

3 回答 3

40

内容类型符合规范 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 时。

于 2013-02-19T16:52:36.643 回答
0

如果(我绝不是说这是正确的方法)您只想从字节数组中保存数据,您应该查看如何读取 POST 正文: Reading POST body with bottle.py Reading the data and then创建一个新文件应该可以解决问题。

于 2015-12-22T09:34:32.870 回答
0

基于@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);

    }
于 2019-09-17T05:59:25.230 回答