ASP.NET - 上传非常大的文件时无法立即获得错误响应?

当我使用 Postman 尝试将大文件上传到我的服务器(用 .NET Core 2.2 编写)时,Postman 立即显示错误HTTP Error 404.13 - Not Found:The request filtering module is configured to deny a request that exceeds the request content length


但是,当我使用代码上传那个大文件时,它会卡在发送文件的线路上。


我的客户代码:


    public async void TestUpload() {

        StreamContent streamContent = new StreamContent(File.OpenRead("D:/Desktop/large.zip"));

        streamContent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"large.zip\"");

        MultipartFormDataContent multipartFormDataContent = new MultipartFormDataContent();

        multipartFormDataContent.Add(streamContent);

        HttpClient httpClient = new HttpClient();

        Uri uri = new Uri("https://localhost:44334/api/user/testupload");

        try {

            HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(uri, multipartFormDataContent);

            bool success = httpResponseMessage.IsSuccessStatusCode;

        }

        catch (Exception ex) {


        }

    }


我的客户端代码卡在了 line HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(uri, multipartFormDataContent),而服务器没有收到任何请求(我使用断点来确保这一点)。


如果文件较大,它会卡住更长时间。查看任务管理器,我可以看到我的客户端程序使用了大量的 CPU 和磁盘,因为它实际上是将文件上传到服务器。过了一会儿,代码移动到下一行,即


bool success = httpResponseMessage.IsSuccessStatusCode

然后通过阅读响应内容,我得到了与Postman完全相同的结果。


现在我想知道如何立即获取错误以便能够及时通知用户,我不想等待很长时间。


请注意,当我使用 Postman 上传大文件时,我的服务器也没有收到任何请求。我想我错过了一些东西,也许我的客户端代码有问题。


编辑:实际上我认为这是客户端错误。但如果是服务器端错误,那么对我来说仍然没有太大意义。因为,让我理清思路。我想创建这个可以跨项目使用的小助手类,也许我也可以与我的朋友分享。所以我认为它应该能够像Postman一样,尽快确定错误。如果邮递员能做到,我也能。


EDIT2:很奇怪,今天我发现邮递员事先不知道服务器是否接受大请求,我上传了一个大文件,我看到它实际上将整个文件发送到服务器,直到得到响应。现在我不再相信自己了,为什么我认为邮递员提前知道错误,我一定是愚蠢的。但这确实意味着我找到了一种比 Postman 更好的方法来完成我的工作,所以我认为这个问题可能对某人有用。


森栏
浏览 145回答 2
2回答

狐的传说

您的问题与服务器端 C# 代码无关。由于客户端和服务器之间发生的事情(我所说的“服务器”是指 IIS、Apache、Nginx...,而不是服务器端代码),您的请求会被卡住。在 HTTP 中,大多数客户端在发送所有请求数据之前不会读取响应。因此,即使您的服务器发现请求太大并返回错误响应,客户端也不会读取该响应,直到服务器接受整个请求。当涉及到服务器端时,您可以检查这个问题,但我认为在客户端处理它会更方便,通过在将文件发送到服务器之前检查文件大小(这基本上是Postman在做的事情)你的情况)。

PIPIONE

你的信息确实帮助我思考如何做我想做的事。我正在做的是:首先,创建一个空ByteArrayContent请求,其中包含ContentLength我要上传到服务器的文件的名称。二是HttpResponseMessage = await HttpClient.SendAsync(HttpRequestMessage)围成一圈try-catch。该catch块被捕获,HttpRequestException因为我正在发送一个带有文件长度的请求,但我的实际内容长度是 0,所以它会抛出一个HttpRequestException带有消息的Cannot close stream until all bytes are written。如果代码到达该catch块,则意味着服务器允许文件大小或更大的请求。如果没有异常并且代码移动到下一行,那么如果HttpResponseMessage.StatusCode是404,则意味着服务器拒绝大于文件大小的请求。HttpResponseMessage.StatusCode不是404 的情况永远不会发生(不过我不确定这一点)。到目前为止我的最终代码:    private async Task<bool> IsBigRequestAllowed() {        FileStream fileStream = File.Open("D:/Desktop/big.zip", FileMode.Open, FileAccess.Read, FileShare.Read);        if(fileStream.Length == 0) {            fileStream.Close();            return true;        }        HttpRequestMessage = new HttpRequestMessage();        HttpMethod = HttpMethod.Post;        HttpRequestMessage.Method = HttpMethod;        HttpRequestMessage.RequestUri = new Uri("https://localhost:55555/api/user/testupload");        HttpRequestMessage.Content = new ByteArrayContent(new byte[] { });        HttpRequestMessage.Content.Headers.ContentLength = fileStream.Length;        fileStream.Close();        try {            HttpResponseMessage = await HttpClient.SendAsync(HttpRequestMessage);            if (HttpResponseMessage.StatusCode == HttpStatusCode.NotFound) {                return false;            }            return true; // The code will never reach this line though        }        catch(HttpRequestException) {            return true;        }    }注意:请注意,我的方法仍然存在问题。我的代码的问题是ContentLength属性,它不应该是文件的长度,它应该更大。例如,如果我的文件长度正好是1000字节,那么如果文件成功上传到服务器,那么Request服务器获取到的ContentLength值就更大。因为它HttpClient不仅仅发送文件的内容,还必须另外发送很多信息。它必须发送边界、内容类型、连字符、换行符等...一般来说,您应该事先找出将与文件一起发送的确切字节,HttpClient以使这种方法完美工作(我仍然不这样做)到目前为止我还不知道,我的时间已经不多了。我稍后会找出并更新我的答案)。现在,我可以立即提前确定服务器是否可以接受与用户想要上传的文件一样大的请求。
打开App,查看更多内容
随时随地看视频慕课网APP