通过Windows Phone 8.1 Silverlight Httpclient以POST multipart/form-data上传文件到Python服务器时文件损坏
最开始,我在使用 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);
}