当前位置: 首页 > news >正文

深度解析源码之SpringMVC文件上传为什么要用POST请求还要设置请求头

深度解析源码之SpringMVC文件上传为什么要用POST请求还要设置请求头

从本篇文章开始,来逐步介绍里面每一步的细节处理流程。
首先看到doDispatch方法的第一个重要操作就是校验文件上传请求。代码如下:
在这里插入图片描述
这个方法是如何校验文件上传请求的呢? 在看这个方法之前,我们先来回忆回忆,之前在写文件上传前端代码的时候,有两个约定俗成的原则:

  • 请求方式要是POST类型的
  • 要设置enctype属性为"multipart/form-data"类型

我们带着这两个约定的原则来看看SpringMVC中是如何来判断文件上传请求的,打开checkMultipart方法的代码,核心代码如下:
在这里插入图片描述
在上面代码第2行这有个判断,调用了multipartResolver的isMultipart方法,这个对象我们在之前介绍Spring九大组件时提到过,它是SpringMVC九大组件中的其中一个,在SpringMVC九大组件初始化的时候,会从容器中去获取这个组件,如下:
在这里插入图片描述
如果我们在Spring容器中没有装配这个类型的Bean,那么应用就没办法支持SpringMVC的文件上传。 我们继续看上面的multipartResolver的isMultipart是干嘛用的呢?

先来看看官方的解释:
在这里插入图片描述
这个方法就是来看看request请求中的content-type是否为"multipart/form-data"类型的。也就是我们在form表单中设置的enctype属性。下面来看看这个方法的实现。

MultipartResolver本身是SpringMVC提供的一个文件上传的标准化接口,我们可以基于这个接口来实现自己的文件上传逻辑,但是在SpringMVC中,对这个接口提供了一个默认的实现,在spring-web这个模块中,对应的实现类的类名是CommonsMultipartResolver,我们来看看这个实现类里面的逻辑:

在这里插入图片描述

里面直接调用了commons-fileupload组件的isMultipartContent方法,这个方法是apache提供的一个文件上传组件,对应的实现如下:

在这里插入图片描述
我们看到,在66行,第一个判断逻辑是判断是否为POST请求,所以验证了之前我们提到的文件上传第一个原则,要是POST类型的请求。

如果是POST请求,将会再去调用isMultipartContent方法,校验HTTP请求头信息中的Context-Type属性,如下:

在这里插入图片描述
在这里插入图片描述
我们看到上面的if判断中,只是校验了Content-Type是否是"multipart/“开头的,但是并不是一定要是"multipart/form-data”,那就只有一种可能,就是还有其他类型的Content-Type可以支持文件上传了。

那么判断它是文件上传请求之后呢?

那当然是要解析文件上传请求了,也就是下面代码中的红框部分了
在这里插入图片描述
这个方法里面就是将普通的HttpServletRequest中的文件信息进行解析,然后封装为MultipartHttpServletRequest对象,代码如下:

在这里插入图片描述
默认不会走延迟解析这种方式,直接解析request请求,在这个parseRequest方法中就是一系列commons-fileupload组件的操作了,如下:

在这里插入图片描述
这个parseRequest方法再往里,就是从请求中读取文件输入流,然后封装到MultipartParsingResult中,最后再把MultipartParsingResult包装为一个文件请求对象返回。commons-fileupload中的操作,有兴趣可以留言我们再展开聊。

这一切准备就绪之后,就回到我们最开始的doDispatch方法中了,如下
在这里插入图片描述

如果返回的请求和原始请求不一样,就表示解析到了文件,再下面的步骤就会进行文件的写文件操作。

对于文件请求的判断我们就介绍到这,可以自己结合代码捋一捋。文章结尾我们再来聊一个问题:

文件上传为什么一定得是POST请求方式,Content-Type为什么一定得是"multipart/form-data"等方式?

请求用GET还是POST,就得看他们有什么区别,我们都知道,最大的一个区别就是GET请求能传输的数据一次性最多只能到1024字节,而POST请求则没有限制,所以一般传文件,请求数据肯定都相对比较大,就得用POST请求。

为什么Context-Type这个请求头就一定得是"multipart/form-data",这个没有为什么,就是"RFC1867"协议中定义的一个文件上传标准。也就是"互联网工程任务组"定义的一些标准属性,属于一些底层协议层面的标准,那么你上层应用想要用这种功能,就必须要遵守人家定义的这个标准。

码字实属不易,如果有收获,请动动手指,点个赞和关注鼓励一下呗!

相关文章:

  • 消息中间件如何选型 图解 Kafka vs RabbitMQ vs RocketMQ 的差异
  • 372. 超级次方
  • 盘点:2022年豆瓣评分8.0以上的计算机书籍有哪些?
  • WPF之调用Iconfont
  • FPGA:Vivado基于IP集成的计数器设计(3)
  • 【GD32F427开发板试用】+软件IIC(OLED显示)
  • 【机器学习】逻辑回归(理论)
  • SAP ABAP 代码修改自动比较对象版本一致
  • Redis应用2(Redison)
  • 【linux】之网络安全
  • Open3D 点云最小二乘法拟合二次曲面(Python版本)
  • 大坝安全监测解决方案 水库大坝安全监测系统改造工程方案
  • 文件操作详解
  • 多线程~实现一个自己的线程池,以及基于单例模式的线程池
  • 手撕Pytorch源码#1.Dataset类 part1
  • 【jQuery】实现文件上传和loading效果
  • 编写设备驱动之i2c_client
  • M1配置Flutter环境及运行项目常见问题解决方法
  • 应用性能监控系统为企业SAP做定制分析
  • 《Linux Shell脚本攻略》学习笔记-第八章