简体   繁体   English

RestSharp可以在不使用多部分内容类型的情况下发送二进制数据吗?

[英]Can RestSharp send binary data without using a multipart content type?

I have been using AddParameter to include XML bodies in my HTTP requests: 我一直在使用AddParameter在我的HTTP请求中包含XML主体:

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

However, this does not seem to work for non-string bodies. 但是,这似乎不适用于非字符串体。 (RestSharp's Http.RequestBody is a string for some reason.) I tried using AddFile() , but I can't find any way to avoid encoding the "file" as multipart/form , even if I've only supplied a single object. (RestSharp的Http.RequestBody由于某种原因是一个字符串。)我尝试使用AddFile() ,但我找不到任何方法来避免将“文件”编码为multipart / form ,即使我只提供了一个对象。

I'm not at all opposed to underhanded reflection to solve this problem, but I'm hoping to avoid modifying the source just to send arbitrary data in an HTTP request. 我完全不反对解决这个问题的反思,但我希望避免修改源只是为了在HTTP请求中发送任意数据。

Edit: regarding the requests I'm trying to send, they just look like this: 编辑:关于我要发送的请求,它们看起来像这样:

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

<arbitrary bytes>

Ideally, I'd like to use the same calls to send a different content type: 理想情况下,我想使用相同的调用来发送不同的内容类型:

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

<other arbitrary bytes>

There have been some modifications made in the latest version that allow a single file to be used without creating a multipart form request. 在最新版本中进行了一些修改,允许在不创建多部分表单请求的情况下使用单个文件。 Here is a gist that shows and example: 这是一个显示和示例的要点:

https://gist.github.com/hallem/5faaa6bebde50641e928 https://gist.github.com/hallem/5faaa6bebde50641e928

I ran into the same issue. 我遇到了同样的问题。 I had to upload exactly one file and use a specific content type for communicating with an REST Interface. 我必须上传一个文件并使用特定的内容类型与REST接口进行通信。 You could modify Http.RequestBody to byte[] (and all dependencies on that), but i think its easier this way: 您可以将Http.RequestBody修改为byte [](及其所有依赖项),但我认为这样更容易:

I modified RestSharp, so that it only use Multipart Encoding when number of Files > 1 or number of Files = 1 and there is also body or other post data set. 我修改了RestSharp,因此当文件数> 1或文件数= 1时,它只使用Multipart Encoding,并且还有正文或其他帖子数据集。

You have to modify Http.cs on Line 288 from 你必须修改288行的Http.cs

if(HasFiles)

to

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

For Http.Sync.cs modify PreparePostData from 对于Http.Sync.cs,修改PreparePostData

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

    PreparePostBody(webRequest);
}

to

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);
}

If you use the async version, you have to modify the code similar to the above in Http.Async.cs. 如果使用异步版本,则必须在Http.Async.cs中修改与上面类似的代码。

Now u can use RestSharp like this 现在你可以像这样使用RestSharp

IRestRequest request = new RestRequest("urlpath", Method.PUT);
request.AddHeader("Content-Type", "application/zip");
request.AddFile("Testfile", "C:\\File.zip");

Client.Execute(request);

AddFile also provides an overload for setting direct byte[] data instead of a path. AddFile还提供了用于设置直接byte []数据而不是路径的重载。 Hope that helps. 希望有所帮助。

In the latest version of RestSharp at the time of writing (version 104), the modification needs to be in Http.Sync.cs , method PreparePostData, which should read as: 在编写本文时的最新版本的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);
    }

I had the same problem, but I didn't fancy forking the code and I didn't like the alternative suggested by Michael as the documentation says "RequestBody: Used by AddBody() (not recommended to use directly)". 我有同样的问题,但我并不喜欢分叉代码,我不喜欢迈克尔提出的替代方案,因为文档说“RequestBody:由AddBody使用(不建议直接使用)”。

Instead I replaced the RestClient.HttpFactory with my own: 相反,我用我自己的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);

Where Bytes and FactoryWithContent look like: 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; }
}

I had the same issue. 我遇到过同样的问题。 Turned out that RestSharp behaves in a little odd way. 原来,RestSharp表现得有些奇怪。

NOT WORKING: 不工作:

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

WORKING (Add content-type as name): 工作(添加内容类型作为名称):

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
});

I tried this solution based on a comment here: https://github.com/restsharp/RestSharp/issues/901 我根据这里的评论尝试了这个解决方案: https//github.com/restsharp/RestSharp/issues/901

which states "...name value will be used as Content-Type Header and contentType value will be ignored." 其中声明“...名称值将用作Content-Type标头,而contentType值将被忽略。”

You dont have to add the value as the Content-Type parameter as well, but I fear that a future bug-fix might change the behaviour and then requiring the Content-Type to be used instead of name. 您不必将值添加为Content-Type参数,但我担心未来的错误修复可能会改变行为,然后要求使用Content-Type而不是name。

Modifications to Http.Async.cs are also necessary for the RequestStreamCallback method. RequestStreamCallback方法也需要对Http.Async.cs进行修改。 I'm actually working on getting this fix into the repo and published to Nuget as I'm helping to maintain the project now. 我正在努力将这个修复程序放到repo中并发布到Nuget,因为我现在正在帮助维护项目。 Here's a link to the issue that's been created for this: https://github.com/restsharp/RestSharp/issues/583 以下是为此创建的问题的链接: https//github.com/restsharp/RestSharp/issues/583

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM