使用RestSharp发送HTTP POST Multipart/form-data字段

27

我在使用RestSharp处理一个REST API时遇到了问题,这是我正在开发的项目所需的。我需要发送的请求包括三个部分:一个API密钥头、一个要上传的文件和一堆JSON格式的数据。该API要求使用"数据"作为表单字段名来发送数据部分。由于在请求正文中命名了字段"data",出现了问题。

我的代码如下:

var request = new RestRequest(UPLOAD_DOC_URLSEGMENT, Method.POST)
{
    RequestFormat = DataFormat.Json,
    AlwaysMultipartFormData = true,
    JsonSerializer = new RestSharpJsonDotNetSerializer(customSerializer)
};

if (doc is DocA)
    request.AddParameter("data",doc as DocA,ParameterType.RequestBody);
    //request.AddBody(doc as DocA);
else
    request.AddParameter("data", doc as DocB,ParameterType.RequestBody);
    //request.AddBody(doc as DocB);

request.AddFile("file", doc.File.FullName);

你可以看到我已经尝试使用request.AddBody(doc)方法和request.AddParameter(name, object, type)方法。两者都似乎未能正确发送数据,因为我从服务器收到的响应是缺少必需参数。使用Fiddler,我可以看到二进制数据,但从这些方法中看不到JSON数据。我查阅了RestSharp文档,但找不到任何允许我指定表单数据主体的特定“字段”名称为“data”的内容,这就是我遇到问题的原因。我在这里做错了什么?

编辑:通过使用Fiddler进行进一步检查,似乎它根本没有将我的JSON数据添加到HTTP请求的主体中。然而,在上载之前的断点处,我可以在参数列表(和文件列表)中看到所有内容被序列化了。当使用Fiddler进行检查时,我看到了文件二进制数据,然后是一个multipart/form-data边界,然后什么也没有。我会认为这就是我的数据应该出现的地方...


我已经编辑了你的标题。请参考“问题的标题应该包含“标签”吗?”,在那里达成共识是“不应该”。 - John Saunders
抱歉!刚刚看了那篇文章,感谢您的编辑。 - JNYRanger
我也在寻找它的答案。@JNYRanger,你找到答案了吗?如果有解决方案,请告诉我。先谢谢了。 - Keval Langalia
@KevalLangalia 不是。我最终放弃了RestSharp,使用标准的HttpWebRequest类和JSON.NET创建了自己的REST客户端。 - JNYRanger
针对未来的访问者,这个问题已经在RestSharp上得到了修复。讨论线程:https://github.com/restsharp/RestSharp/issues/524 - kmonsoor
2个回答

18

因为使用AddBody方法会自动清除多部分表单图像并且无法发送它们,所以我通过绕过这个问题来完成这个过程。 你必须使用add参数。

要解决这个问题,您可能需要在通信的两端都做一些工作。

要从客户端发送消息,请执行以下操作:

new RestRequest("<Your URI>");
request.AddParameter("request", tokenRequest.ToJson());
request.AddFile("front", frontImage.CopyTo, "front");
request.AddFile("back", backImage.CopyTo, "back");
request.AddHeader("Content-Type", "multipart/form-data");

在我的Web服务端,我将JSON作为方法参数接受,并手动获取文件流的引用:

public JsonResult MyService(StoreImageRequest request)
{
    var frontImage = HttpContext.Request.Files["front"].InputStream;
    var backImage = HttpContext.Request.Files["front"].InputStream;
}

这段代码对你有用吗,@C Tierney?我想上传一个文件和一些参数,但是我无法让它工作。我总是得到状态码为0的响应。 {"底层连接已关闭:发送时发生意外错误。"} - Adam
tokenRequest 当然是未定义的,因此会抛出异常...第一行应该是 'var tokenRequest =' 后面跟着一行吗?还是说那一行应该是 'var request ='?我遇到了这个问题/异常,这段代码片段对我来说毫无用处。 - Traderhut Games
令牌是我想要传递的JSON对象,而背面图像和正面图像也是在其上的代码变量。我们对支票图像进行标记化处理,tokenRequest是我们想要与安全存储的支票图像关联的数据集一起传递的对象。很抱歉我没有表述得更清楚。 - C Tierney

4

使用JSON和文件上传的多部分请求

如果您的服务器可以处理同时包含JSON和文件部分的多部分请求,则:

客户端代码:

        var req = new RestRequest(UPLOAD_DOC_URLSEGMENT, Method.POST);

        req.RequestFormat = DataFormat.Json;
        req.AddBody(doc);

        req.AddFileBytes("TestImage", Properties.Resources.TestImage, "TestImage.jpg");

        req.AddHeader("apikey", "MY-API-KEY");
        var resp = restClient.Execute<ApiResult>(req);

服务端代码:

在服务器端,这样的多部分请求应该按以下方式处理:

    [HttpPost]
    public JsonResult UploadDoc()
    {
        // This is multipart request. So we should get JSON from http form part:
        MyDocModel doc = JsonConvert.DeserializeObject<MyDocModel>(Request.Form[0]);
        
        foreach (string fileName in request.Files)
        {
            HttpPostedFileBase file = request.Files[fileName];
        }

前面的答案通过使用一个解决方法 tokenRequest.ToJson() 来解决主题中声明的需求。而这个答案则提出了使用 req.RequestFormat = DataFormat.Json 的方法,它是有效的。 - epox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接