RestSharp能否在不使用multipart content类型的情况下发送二进制数据?

11

我一直在使用AddParameter将XML主体包含在我的HTTP请求中:

request.AddParameter(contentType, body, ParameterType.RequestBody);

然而,对于非字符串体似乎不起作用(RestSharp的Http.RequestBody出于某种原因是一个字符串)。我尝试使用AddFile(),但我找不到任何避免将“文件”编码为multipart/form的方法,即使我只提供了一个对象。

我并不反对使用一些欺骗手段来解决这个问题,但我希望避免修改源代码以便在HTTP请求中发送任意数据。

编辑:关于我正在尝试发送的请求,它们看起来像这样:

PUT ... HTTP/1.1
Accept: application/vnd...
Authorization: Basic ...
Content-Type: application/octet-stream

<arbitrary bytes>
理想情况下,我希望使用相同的调用来发送不同类型的内容:
PUT ... HTTP/1.1
Accept: application/vnd...
Authorization: Basic ...
Content-Type: application/vnd...

<other arbitrary bytes>

我不完全确定我是否理解了这个问题;所有的http请求都是文本;如果你发送二进制数据,那么它会被编码为base64(通常是),这仍然是文本,尽管是不可读的文本。 - Russ Clarke
为了使通常的位数合格,还有其他方案,如uuencode,它允许更好的压缩,但归根结底,使用一种编码,允许字节的完整值在HTTP支持的可打印字符范围内表示。 - Russ Clarke
1
@RussC:HTTP正文可能包含任何字节值。也许我没有理解你的意思? - ladenedge
2
回到你最初的问题,目前还没有支持这个功能,而且这是一个非常罕见的请求,所以我不太可能自己添加它。我建议直接使用HttpWebRequest。 - John Sheehan
1
我有类似的需求:我需要仅使用参数而不是文件来发布multipart/form-data。在https://github.com/restsharp/RestSharp/pull/385上提交了一个pull请求,但没有得到任何关注。 - Martin Meixger
显示剩余5条评论
6个回答

9

4
对于那些像我一样因为标题写着“文件”而跳过这个答案的人,我提醒你们:它并不一定是文件。关键特征在于,如果你使用 request.AddParameter("application/pdf", documentBytes, ParameterType.RequestBody) 来添加正文内容,documentBytes 是一个 byte[] 数组,那么这些字节将直接作为指定的 Content-Type(这里是 application/pdf)发送。 - meustrus

5

我遇到了同样的问题。我必须上传一个文件并使用特定的内容类型与REST接口通信。你可以将Http.RequestBody修改为byte[](以及所有依赖项),但我认为这样更容易:

我修改了RestSharp,使其仅在文件数量> 1或文件数量= 1且还设置了正文或其他提交数据时才使用多部分编码。

您必须修改Http.cs中的第288行,从

if(HasFiles)

为了

if(Files.Count > 1 || (Files.Count == 1 && (HasBody || Parameters.Any())))

对于 Http.Sync.cs,修改 PreparePostData 方法:

private void PreparePostData(HttpWebRequest webRequest)
{
    if (HasFiles)
    {
        webRequest.ContentType = GetMultipartFormContentType();
        using (var requestStream = webRequest.GetRequestStream())
        {
            WriteMultipartFormData(requestStream);
        }
    }

    PreparePostBody(webRequest);
}

为了

private void PreparePostData(HttpWebRequest webRequest)
{
    // Multiple Files or 1 file and body and / or parameters
    if (Files.Count > 1 || (Files.Count == 1 && (HasBody || Parameters.Any())))
    {
        webRequest.ContentType = GetMultipartFormContentType();
        using (var requestStream = webRequest.GetRequestStream())
        {
            WriteMultipartFormData(requestStream);
        }
    }
    else if (Files.Count == 1)
    {
        using (var requestStream = webRequest.GetRequestStream())
        {
            Files.Single().Writer(requestStream);
        }
    }

    PreparePostBody(webRequest);
}

如果你使用的是异步版本,那么你需要修改 Http.Async.cs 中类似上面的代码。现在,你可以像这样使用 RestSharp。
IRestRequest request = new RestRequest("urlpath", Method.PUT);
request.AddHeader("Content-Type", "application/zip");
request.AddFile("Testfile", "C:\\File.zip");

Client.Execute(request);

AddFile还提供了一种重载方式,用于设置直接的byte[]数据而非路径。希望这有所帮助。


1
值得一提的是,另一种修改RestSharp的方法是将其默认编码更改为Windows-1252,并将以此编码的字符串传递给AddBody。事实证明,一个1252编码的字符串等同于二进制 - ladenedge

5
在撰写本文时最新版本的RestSharp(版本104)中,需要在Http.Sync.cs文件中修改PreparePostData方法,修改后应该如下所示:
    private void PreparePostData(HttpWebRequest webRequest)
    {

        // Multiple Files or 1 file and body and / or parameters
        if (Files.Count > 1 || (Files.Count == 1 && (HasBody || Parameters.Count>0)))
        {
            webRequest.ContentType = GetMultipartFormContentType();
            using (var requestStream = webRequest.GetRequestStream())
            {
                WriteMultipartFormData(requestStream);
            }
        }
        else if (Files.Count == 1)
        {
            using (var requestStream = webRequest.GetRequestStream())
            {
                Files[0].Writer(requestStream);
            }
        }
        PreparePostBody(webRequest);
    }

4
我曾经遇到过同样的问题,但我不想分叉代码,也不喜欢Michael提出的替代方案,因为文档中说“RequestBody:由AddBody()使用(不建议直接使用)”。
相反,我用自己的替换了RestClient.HttpFactory:
RestClient client = GetClient();

var bytes = await GetBytes();
client.HttpFactory = new FactoryWithContent { GetBytes = () => new Bytes(bytes, "application/zip") };

var request = new RestRequest();
return await client.ExecutePostTaskAsync(request);

Bytes和FactoryWithContent的样子如下:

public class Bytes
{
    public Bytes(byte[] value, string type)
    {
        Value = value;
        Type = type;
    }

    public byte[] Value { get; private set; }
    public string Type { get; private set; }
}

public class FactoryWithContent : IHttpFactory
{
    public IHttp Create()
    {
        var http = new Http();

        var getBytes = GetBytes;
        if (getBytes != null)
        {
            var bs = getBytes();
            http.RequestBodyBytes = bs.Value;
            http.RequestContentType = bs.Type;
        }

        return http;
    }

    public Func<Bytes> GetBytes { get; set; }
}

1
因此,我厌恶RestSharp - hellboy

3

我遇到了相同的问题。结果发现RestSharp表现得有点奇怪。

不起作用:

request.Parameters.Add(new Parameter() {
  ContentType = "application/x-www-form-urlencoded",
  Type = ParameterType.RequestBody,
  Value = bytes
});

操作步骤(将content-type添加为名称):

request.Parameters.Add(new Parameter() {
  Name = "application/x-www-form-urlencoded", // This is the 'funny' part
  ContentType = "application/x-www-form-urlencoded",
  Type = ParameterType.RequestBody,
  Value = bytes
});

我尝试了这个基于这里的评论的解决方案:https://github.com/restsharp/RestSharp/issues/901,其中指出:“...name value将用作Content-Type标头,而contentType值将被忽略”。
你不必再把值添加为Content-Type参数,但我担心未来的错误修复可能会更改行为,然后需要使用Content-Type代替名称。

0

对于 RequestStreamCallback 方法,需要对 Http.Async.cs 进行修改。我正在努力将此修复程序纳入存储库并发布到 Nuget 中,因为我现在正在帮助维护该项目。这是一个已创建的问题链接:https://github.com/restsharp/RestSharp/issues/583


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