【问题标题】:Posting large file React.js & .net 5发布大文件 React.js 和 .net 5
【发布时间】:2021-01-14 19:38:44
【问题描述】:

我有一个 .net 5 API,它有一个端点,它接受一个由 IFormFile 文件、字符串描述和字符串名称组成的模型。

当使用我的反应客户端的 axios 发布表单时,使用 55.500kb 文件一切正常,但是当发布 250,000kb 的文件时,请求似乎没有任何问题离开客户端,但当端点为时整个请求为空命中。

我的 API 端点使用 2147483648 的 RequestSizeLimit 进行修饰,并在 web.config 中进行镜像。

我猜原因是发布的文件太大但不能 100% 确定。如果这是我需要以某种方式流式传输或分块请求的原因,还是其他原因导致此问题?

React 函数发布表单:

    handleSubmit = async () => {
        this.setState({ componentState: LOADING }, async () => {
            let form = new FormData();
            form.append("title", this.state.title);
            form.append("reference", this.state.reference);
            form.append("description", this.state.description);
            form.append("price", this.state.price);
            form.append("scormFile", this.state.file);

            let response = await uploadCourseAsync(form);
            
            if (response.isSuccessStatusCode) {
                this.setState({ componentState: SUCCESS });
            }
            else {
                this.setState({ errors: response.errors })
            }
        })
    }

.net 端点接收请求:

        [RequestSizeLimit(2147483648)]
        [HttpPost("UploadCourse")]
        public async Task<IActionResult> UploadCourse([FromForm] CreateCourseCommand command)
        {
            var ms = new MemoryStream();
            await command.ScormFile.CopyToAsync(ms);
            var byteArrayContent = new ByteArrayContent(ms.ToArray());
            var multipartContent = new MultipartFormDataContent
            {
                {byteArrayContent, command.ScormFile.Name, command.ScormFile.FileName},
                {new StringContent(command.Description), "Description"},
                {new StringContent(command.Reference), "Reference"},
                {new StringContent(command.Price), "Price"},
                {new StringContent(command.Title), "Title"},
                {new StringContent(User.Claims.FirstOrDefault(c => c.Type == "Id")?.Value ?? string.Empty), "UploadedById"},
                {byteArrayContent, command.ScormFile.Name, command.ScormFile.FileName}
            };

            var url = _serviceUrlConfig.CourseService + "/course/uploadcourse";
            var myHttpClient = new HttpClient();
            var response = await myHttpClient.PostAsync(url, multipartContent);
            return Ok(response);
        }

任何建议都会很棒,在此先感谢。

【问题讨论】:

    标签: c# reactjs file-upload .net-5


    【解决方案1】:

    我在没有任何客户所说的更改的情况下解决了这个问题。发布表单时,使用 web.config 设置的限制和装饰控制器的属性似乎被忽略了。解决方法是在 Startup.cs 中的 ConfigureServices 方法中添加如下代码

             services.Configure<FormOptions>(o =>  
                {
                    o.ValueLengthLimit = int.MaxValue;
                    o.MultipartBodyLengthLimit = long.MaxValue;
                    o.MultipartBoundaryLengthLimit = int.MaxValue;
                    o.MultipartHeadersCountLimit = int.MaxValue;
                    o.MultipartHeadersLengthLimit = int.MaxValue;
                });
    

    【讨论】:

      【解决方案2】:

      POST 消息最大值。大小通常由 http 服务器限制为 2 GB。此代码允许您下载任何大小的文件。

      反应组件:

      import React, { useState } from 'react';
      import { v4 as uuid } from 'uuid';
      
      export default function LargeFileUploader(props) {
          const BYTES_PER_CHUNK = 10485760; // 10MB chunk sizes.
          var start;
          var part;
          var SIZE = 0;
          var xhr;
          var fileGuid = '';
          const [file, setFile] = useState('');
      
          function sendRequest() {
              SIZE = file.size;
              start = 0;
              part = 0;
              xhr = new XMLHttpRequest();
              xhr.addEventListener("load", uploadComplete, false);
              uploadFile(part);
          }
          function uploadFile() {
              var blobFile = file.slice(start, BYTES_PER_CHUNK + start);
              var fd = new FormData();
              fd.append("file", blobFile);
              fd.append("fileguid", fileGuid);
              fd.append('part', part);
              fd.append('rawFileName', file.name);
              fd.append('partsTotal', Math.ceil(SIZE / BYTES_PER_CHUNK));
      
              var url = process.env.PUBLIC_URL + "/" + 'Files' + "/" + 'Upload';
              xhr.open("POST", url);
              xhr.setRequestHeader('Cache-Control', 'no-cache');
              xhr.send(fd);
          }
      
          function uploadComplete(event) {
              if (event.currentTarget.status === 200) {
                  if (start < SIZE) {
                      start = start + BYTES_PER_CHUNK;
                      part++;
                      uploadFile();
                  }
              } else {
                  alert('error');
              }
          }
      
          return (
              <div className="largeFileUploader">
                  <form onSubmit={(event) => {
                      event.preventDefault();
                      fileGuid = uuid();
                      sendRequest();
                  }}>                
                      <div>
                          <input type="file" multiple={false}
                              onChange={(event) => {
                                  setFile(event.target.files[0]);
                              }}
                          />
                      </div>
                      <div>
                              <button type="submit" disabled={!file}>Upload</button>
                      </div>
                  </form>
              </div>
          )
      }
      

      .NET 5 控制器方法:

          [HttpPost]        
          [Route("Upload")]
          public async Task<IActionResult> Upload(IFormCollection formData)
          {
              try
              {
                  var part = int.Parse(formData["part"].ToString());
                  var fileGuid = Guid.Parse(formData["fileGuid"].ToString());
                  var rawFileName = formData["rawFileName"].ToString();
                  string filePath = Path.Combine(_appConfig.DocumentFilesPath, fileGuid.ToString() + "." + rawFileName.Split(".").Last());
      
                  using (Stream fileStream = new FileStream(filePath, part == 0 ? FileMode.Create : FileMode.Append))
                  {
                      await formData.Files.First().CopyToAsync(fileStream);
                      fileStream.Close();
                  }
      
                  return Ok();
              }
              catch (Exception exception)
              {
              }
      
              return StatusCode(500);
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-21
        • 2018-06-29
        • 2017-01-13
        • 1970-01-01
        • 2021-02-22
        • 2020-11-28
        • 2023-02-07
        • 1970-01-01
        相关资源
        最近更新 更多