为什么我会收到404尝试将大文件发布到Core Web API的信息 [英] Why do I get a 404 trying to post a large file to a Core Web API

查看:78
本文介绍了为什么我会收到404尝试将大文件发布到Core Web API的信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对于在HttpClient和Web API之间进行文件传输非常陌生,因此请原谅我的代码中的任何无知和猜测.我一直在尝试将使用System.IO.Compression.ZipFile创建的文件发布到我的Web API大约一天,并且总是收到404响应.如果我发布的流为空,则会调用API操作方法,因此我知道404是由于内容而不是URI.

I am very new to file transfer between HttpClient and a Web API, so please excuse any ignorance and guesswork in my code. I have been trying to post a file created with System.IO.Compression.ZipFile to my web API now for about a day, and always I get a 404 response. If I post with an empty stream, the API action method is invoked, so I know the 404 is due to content and not the URI.

此方法在尝试发布文件的客户端WPF应用程序中:

This method is in the client WPF application that attempts to post the file:

public async Task PostDirAsync(string localDirPath, string serverDir)
{
    var sourcePath = Path.Combine("Temp", Guid.NewGuid() + ".zip");
    ZipFile.CreateFromDirectory(localDirPath, sourcePath, CompressionLevel.Fastest, true);
    StreamContent streamContent;
    using (var fs = File.Open(sourcePath, FileMode.Open))
    {
        var outStream = new MemoryStream();
        await fs.CopyToAsync(outStream);
        outStream.Position = 0;
        streamContent = new StreamContent(outStream);
    }
    streamContent.Headers.Add("Content-Type", "application/octet-stream");
    var resp = await _client.PostAsync("api/File/PostDir?serverPath={WebUtility.UrlEncode(serverDir)}", streamContent);
}

这是Web API中接收帖子的操作方法,但前提是我在尝试发布之前没有执行outStream.Position = 0;的情况:

And this is the action method in the Web API that receives the post, but only if I don't do the outStream.Position = 0; before attempting to post:

[HttpPost("PostDir")]
[DisableRequestSizeLimit]
public async Task<IActionResult> PostDir(string serverPath)
{           
    var zipName = Path.Combine(_config["QuickDrive:TempDir"], Guid.NewGuid() + ".zip");
    using (var ms = new MemoryStream())
    using (var fileStream = System.IO.File.Create(zipName))
    {
        await Request.Body.CopyToAsync(ms);
        ms.Position = 0;
        await ms.CopyToAsync(fileStream);
    }
    return Ok();
}

action方法被调用并在没有空流的情况下运行而没有错误,但是由于它写入了一个空文件,因此几乎没有用.我在做什么错了?

The action method is invoked and runs without error with an empty stream, but is pretty useless as it writes an empty file. What am I doing wrong?

推荐答案

如注释中所述,您的第一个问题是文件复制中涉及的Stream实例未使用Stream.Position = 0重置.我知道您已经进行了这些更改,但是我只想强调一下,这是一个分为两个部分的解决方案.

As mentioned in the comments, your first problem was that the Stream instances involved in the file copying were not being reset using Stream.Position = 0. I know you've made these changes already, but I just want to emphasise that this is a two-part solution.

第二部分:

在示例代码中,您添加了[DisableRequestSizeLimit]批注,以绕过默认的ASP.NET Core 2.0+ Kestrel请求限制.但是,IIS也有一个限制,默认情况下为30MB.当超出此大小限制时,IIS本身会生成一个404响应,这就是您所看到的.

In your example code, you've added the [DisableRequestSizeLimit] annotation in order to bypass the default ASP.NET Core 2.0+ Kestrel request limits. However, there's also a limit that's imposed by IIS, which is 30MB by default. When this size limit is exceeded, IIS itself generates a 404 response, which is what you're seeing.

此答案说明了如何使用自定义的Web.config(为了完整起见,请参见下文)更改此限制:

This answer explains how to change this limit using a custom Web.config (included below for completeness):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <security>
      <requestFiltering>
        <!-- 1 GB -->
        <requestLimits maxAllowedContentLength="1073741824" />
      </requestFiltering>
    </security>
  </system.webServer>
</configuration>


作为旁注:


As somewhat of a side note:

除非有特殊原因,否则可以避免在代码中使用MemoryStream,而直接将fs传递到new StreamContent(...)中.您可以对Request.Body流执行类似的操作,并将其直接复制到输出FileStream中.最终结果是:

Unless you have a specific reason to do so, you can avoid the use of MemoryStream in your code and just pass fs directly into new StreamContent(...). You can do something similar with the Request.Body stream and copy that directly into the output FileStream. This would end up with:

public async Task PostDirAsync(string localDirPath, string serverDir)
{
    var sourcePath = Path.Combine("Temp", Guid.NewGuid() + ".zip");
    ZipFile.CreateFromDirectory(localDirPath, sourcePath, CompressionLevel.Fastest, true);

    var streamContent = new StreamContent(File.Open(sourcePath, FileMode.Open));
    streamContent.Headers.Add("Content-Type", "application/octet-stream");
    var resp = await _client.PostAsync("api/File/PostDir?serverPath={WebUtility.UrlEncode(serverDir)}", streamContent);
}

并且:

[HttpPost("PostDir")]
[DisableRequestSizeLimit]
public async Task<IActionResult> PostDir(string serverPath)
{           
    var zipName = Path.Combine(_config["QuickDrive:TempDir"], Guid.NewGuid() + ".zip");
    using (var fileStream = System.IO.File.Create(zipName))
        await Request.Body.CopyToAsync(fileStream );
    return Ok();
}

这篇关于为什么我会收到404尝试将大文件发布到Core Web API的信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆