通过Windows Phone 8.1 Silverlight Httpclient以POST multipart/form-data上传文件到Python服务器时文件损坏

2 投票
1 回答
1867 浏览
提问于 2025-04-18 15:24

最开始,我在使用 Windows Phone 8 的 System.Net.Http 库来把 SD 卡上的图片上传到一个 Python 服务器,代码如下:

    private async void UploadFile()
    {
        try
        {
            // Make sure there is a picture selected
            if (photoStream != null)
            {
                // initialize the client
                // need to make sure the server accepts network IP-based
                // requests. 
                // ensure correct IP and correct port address
                var fileUploadUrl = @"http://IPAddress/";
                var client = new HttpClient();

                // Reset the photoStream position
                // If you don't reset the position, the content lenght
                // sent will be 0
                photoStream.Position = 0;

                // This is the postdata
                MultipartFormDataContent content = new MultipartFormDataContent();
                content.Add(new StreamContent(photoStream), "fn", fileName);

                // upload the file sending the form info and ensure a result.
                // it will throw an exception if the service doesn't return 
                // a valid successful status code
                await client.PostAsync(fileUploadUrl, content)
                    .ContinueWith((postTask) =>
                    {
                        postTask.Result.EnsureSuccessStatusCode();
                    });
            }

            // Disable the Upload button
            btnUpload.IsEnabled = false;

            // reset the image control
            DisplayImage.Source = null;
        }
        catch
        {

        }
    }

在服务器端,我用以下 Python 代码来解码请求:

ctype, pdict = cgi.parse_header(self.headers['content-type'])
data = cgi.parse_multipart(self.rfile, pdict)

这个方法一直有效,直到我把手机换成了 Windows Phone 8.1 Silverlight。因为在 Windows Phone 8.1 Silverlight 中,System.Net.Http 库不再受支持,所以我改用了 Windows.Web.Http,并对代码做了一些修改:

    private async void UploadFile()
    {
        try
        {
            // Make sure there is a picture selected
            if (file != null)
            {
                // initialize the client
                // need to make sure the server accepts network IP-based
                // requests. 
                // ensure correct IP and correct port address
                var fileUploadUrl = new Uri(@"http://IPAddress/", UriKind.Absolute);
                var client = new HttpClient();

                HttpMultipartFormDataContent content = new HttpMultipartFormDataContent();
                HttpStreamContent streamContent = new HttpStreamContent(photoStream);
                content.Add(streamContent, "fn", fileName);

                await client.PostAsync(fileUploadUrl, content);

            }

            // Disable the Upload button
            btnUpload.IsEnabled = false;

            // reset the image control
            DisplayImage.Source = null;
        }
        catch
        {

        }
    }

服务器端的代码没有变化。不过,现在上传的文件中间会不定期插入一些额外的字节,看起来像是 '\r\n10000\r\n' 或者 0D 0A 31 30 30 30 30 0D 0A。而且,这个文件的开头和结尾也有同样的额外字节模式。在服务器上,pdict 把边界映射成类似 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 的东西,但这似乎和之前通过 System.Net.Http 上传文件时的表现是一样的。我尝试在一个小文件上手动去掉这些字节,结果发现文件其他部分是正确的。

那么,这些额外的字节为什么会出现呢?这是 Python 服务器处理 POST 请求时出错了吗?

1 个回答

1

这是我在遇到这个问题时的解决方案:

客户端:

 public async Task UploadImage(byte[] image, string url)
        {
            Stream stream = new System.IO.MemoryStream(image);
            HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());

            Uri resourceAddress = null;
            Uri.TryCreate(url.Trim(), UriKind.Absolute, out resourceAddress);
            Windows.Web.Http.HttpRequestMessage request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Post, resourceAddress);
            request.Content = streamContent;

            var httpClient = new Windows.Web.Http.HttpClient();
            var cts = new CancellationTokenSource();
            Windows.Web.Http.HttpResponseMessage response = await httpClient.SendRequestAsync(request).AsTask(cts.Token);
        }

控制器:

public async Task<HttpResponseMessage> Post()
{
    Stream requestStream = await this.Request.Content.ReadAsStreamAsync();
    byte[] byteArray = null;
    using (MemoryStream ms = new MemoryStream())
    {
        await requestStream.CopyToAsync(ms);
        byteArray = ms.ToArray();
    }
    .
    .
    .
    return Request.CreateResponse(HttpStatusCode.OK);
}

撰写回答