HttpClient上传MultipartFormData来玩2框架

时间:2013-07-27 18:10:27

标签: c# windows-phone-8 playframework-2.0 http-post multipartform-data

我在使用RestSharp客户端的Windows Phone 8项目中有以下代码:

public async Task<string> DoMultiPartPostRequest(String ext, JSonWriter jsonObject, ObservableCollection<Attachment> attachments)
    {
        var client = new RestClient(DefaultUri);
        // client.Authenticator = new HttpBasicAuthenticator(username, password);

        var request = new RestRequest(ext, Method.POST);

        request.RequestFormat = DataFormat.Json;
        request.AddParameter("json", jsonObject.ToString(), ParameterType.GetOrPost);

        // add files to upload
        foreach (var a in attachments)
            request.AddFile("attachment", a.FileBody, "attachment.file", a.ContType);

        var content = await client.GetResponseAsync(request);

        if (content.StatusCode != HttpStatusCode.OK)
            return "error";

        return content.Content;
    }

Fiddler显示生成的标题:

POST http://192.168.1.101:9000/rayz/create HTTP/1.1
Content-Type: multipart/form-data; boundary=-----------------------------28947758029299
Content-Length: 71643
Accept-Encoding: identity
Accept: application/json, application/xml, text/json, text/x-json, text/javascript, text/xml
User-Agent: RestSharp 104.1.0.0
Host: 192.168.1.101:9000
Connection: Keep-Alive
Pragma: no-cache

-------------------------------28947758029299
Content-Disposition: form-data; name="json"

{
    "userId": "2D73B43390041E868694A85A65E47A09D50F019C180E93BAACC454488F67A411",
    "latitude": "35.09",
    "longitude": "33.30",
    "accuracy": "99",
    "maxDistance": "dist",
    "Message": "mooohv"
}
-------------------------------28947758029299
Content-Disposition: form-data; name="attachment"; filename="attachment.file"
Content-Type: image/jpeg

?????JFIF??`?`?????C?  $" &0P40,,0bFJ:Ptfzxrfpn????????np????????|????????????C"$$0*0^44^?p??????????????????????????????????????????????????????`?"??????????????
-------------------------------28947758029299

上面的代码在Play2 API上运行良好。但是,由于RestSharp似乎不稳定,我决定使用Microsoft提供的本机HttpClient。

因此我编写了另一个使用HttpClient执行相同工作的函数:

public async Task<string> DoMultiPartPostRequest2(String ext, JSonWriter jsonObject,
                                                                 ObservableCollection<Attachment> attachments)
    {
        var client = new HttpClient();

        var content = new MultipartFormDataContent();

        var json = new StringContent(jsonObject.ToString());
        content.Add(json, "json");

        foreach (var a in attachments)
        {
            var fileContent = new StreamContent(new MemoryStream(a.FileBody));
            fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = "attachment",
                FileName = "attachment.file"
            };
            fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(a.ContType);
            content.Add(fileContent);
        }

        var resp = await client.PostAsync(DefaultUri + ext, content);

        if (resp.StatusCode != HttpStatusCode.OK)
            return "error";

        var reponse = await resp.Content.ReadAsStringAsync();

        return reponse;
    }

从该代码生成的标头如下:

POST http://192.168.1.101:9000/rayz/create HTTP/1.1
Accept: */*
Content-Length: 6633
Accept-Encoding: identity
Content-Type: multipart/form-data; boundary="e01b2196-d24a-47a2-a99b-e82cc4a2f92e"
User-Agent: NativeHost
Host: 192.168.1.101:9000
Connection: Keep-Alive
Pragma: no-cache

--e01b2196-d24a-47a2-a99b-e82cc4a2f92e
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=json

{
    "userId": "2D73B43390041E868694A85A65E47A09D50F019C180E93BAACC454488F67A411",
    "latitude": "35.09",
    "longitude": "33.30",
    "accuracy": "99",
    "maxDistance": "dist",
    "Message": "test"
}
--e01b2196-d24a-47a2-a99b-e82cc4a2f92e
Content-Disposition: form-data; name=attachment; filename=attachment.file
Content-Type: image/jpeg

?????JFIF??`?`?????C?  $" &0P40,,0bFJ:Ptfzxrfpn????????np????????|????????????C"$$0*0^44^?p????????????????????????????????????????????????????????"??????????????
--e01b2196-d24a-47a2-a99b-e82cc4a2f92e--

到目前为止一切顺利。从我的角度来看,两个标题似乎完全相同。

然而,当我在执行Http.MultipartFormData body = request().body().asMultipartFormData();后调试Play 2 API时,我注意到多部分数据没有被正确解析。

更具体地说,body变量中的multipart字段如下:

MultipartFormData(Map(),List(),List(BadPart(Map(ntent-type -> text/plain; charset=utf-8, content-disposition -> form-data; name=json)), BadPart(Map()), BadPart(Map()), BadPart(Map()), BadPart(Map())),List())

你可以注意到它有几个(在这个例子中实际上是5个)BadParts。 示例:BadPart(Map(ntent-type -> text/plain; charset=utf-8, content-disposition -> form-data; name=json))

谁能看到这里出了什么问题? HttpClient生成的标头是错误的吗?

1 个答案:

答案 0 :(得分:4)

这是解决方案......(黑客)

当边框中有引号时,Play Framework似乎存在问题。

所以我在创建multipart后添加了以下代码以便删除它们:

var content = new MultipartFormDataContent();

foreach (var param in content.Headers.ContentType.Parameters.Where(param => param.Name.Equals("boundary")))
     param.Value = param.Value.Replace("\"", String.Empty);

最后,我必须手动将引号“\”“添加到标题上的特定值,如下所示:

原文:Content-Disposition: form-data; name=attachment; filename=attachment.file 已更改为:Content-Disposition: form-data; name="attachment"; filename="attachment.file"

原文:Content-Disposition: form-data; name=json 已更改为:Content-Disposition: form-data; name="json"

我不认为在标题中的任何地方引用或不引用是错误的,也许应该相应地修改play框架上的解析。