HTTP POST 文件上传到服务器端请求及处理过程解读

一、场景描述

  在互联网开发的过程中,往往需要实现文件上传的功能,我们可以借助比较好的第三方文件服务器:七牛云等等。但是也有一些需要直接通过 HTTP POST 文件到应用服务器进行特殊处理的功能实现。

  通过以上的介绍,就应引申出了这篇文章,Spring Boot 使用 MultipartFile 接收来自表单的 file 文件,然后进行服务器上传是一个项目的基本需求。下面我们就代码加调试的方式来解读整个 HTTP POST 文件到服务器端的整个过程。

二、文件上传
  • 前端我们采用 POST MAN 来实现文件上传的调试工作
    1

  • 服务器端接收文件的源码

    • Controller

      @PostMapping("/Content")
      //@Async(value = ExecuteName.MEDIA)
      public DataResult mediaAudit(@RequestParam(value = "Thumbnail", required = false) MultipartFile thumbnail,
                                   @RequestParam("File") MultipartFile file,
                                   HttpServletRequest request,
                                   HttpServletResponse response)  {
          response.setHeader("Content-Type", "application/json;charset=UTF-8");
          response.setHeader("tid", UUID.randomUUID().toString());
          response.setStatus(HttpServletResponse.SC_OK);
          Boolean result = mediaFrontService.mediaAudit(thumbnail, file, request);
          if (result) {
              return DataResult.success();
          }
          return DataResult.getDataResult(MediaServerResponseCode.MEDIA_BUSY);
      }
      
    • Service

    @Override
    public Boolean mediaAudit(MultipartFile thumbnail, MultipartFile file) {
        try {
            // 缩略图处理
            if (!thumbnail.isEmpty()) {
                // 获取原始文件名称
                String thumbnailFilename = thumbnail.getOriginalFilename();
                // 保存文件
                thumbnail.transferTo(new File("/Users/rambo/Desktop/Temp/" + thumbnailFilename));
            }
    
            // 正文图处理
            if (!file.isEmpty()) {
                // 获取原始文件名称
                String filename = file.getOriginalFilename();
                // 保存文件
                file.transferTo(new File("/Users/rambo/Desktop/Temp/" + filename));
            } else {
                throw new BusinessException(MediaServerResponseCode.MEDIA_PARAMS);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException(MediaServerResponseCode.MEDIA_BUSY.getCode(), e.getMessage());
        }
        return true;
    }
    
三、过程解读
  • 前端请求报文

    • 抓包图
      2

    • 请求行

      # 请求方式 + 请求URL + 请求协议
      POST /Content HTTP/1.1
      
    • 请求头

      # Content-Type 指明数据以 multipart/form-data 来编码
      # 生成一个 boundary 用于分割不同的字段,为避免与正文内容重复,boundary 内容很长很复杂
      Content-Type	multipart/form-data; boundary=--------------------------988921756836113674975210
      
    • 请求体

      传输的是文件,包含文件名和文件类型信息,消息体以 --boundary 标示开始,最后以 --boundary-- 标示结束

      ----------------------------988921756836113674975210
      Content-Disposition: form-data; name="Thumbnail"; filename="thumb.jpg"
      Content-Type: image/jpeg
      
      ÿØÿà™ÿÙ...
      ...
      ...
      ...
      ----------------------------988921756836113674975210
      Content-Disposition: form-data; name="File"; filename="matl.jpg"
      Content-Type: image/jpeg
      
      ÿØÿàJFIF``
      ...
      ...
      ...
      ...
      ÿÛC
      P3ÿÙ
      ----------------------------988921756836113674975210--
      

      P.S
      上传文件的文件体中包含了文件名和文件类型信息

  • 后端业务处理

    • MultipartFile 接口源码解析
      3
      • MultipartFile 继承了 InputStreamSource 接口

      • MultipartFile 封装了获取文件名称、源名称、文件类型等所有上传上来文件的所有信息

      • MultipartFile 可以通过 transferTo 很方便的将文件输出到 dest file 中去,为我们将数据保存到本地提供了极大的便利

四、总结
  • 前端采用 POST 请求,文件以二进制流的方式传输

  • 后端拿到 MultipartFile 以后,通过 MultipartFile 封装的方式直接获取文件所有信息并保存到本地磁盘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值