HTTP中提供了这么多方法,放着不用简直浪费!流行使用POST上传文件是因为当年的Web没有太多API的支持,只能用表单来上传文件,所以后来大家也习惯了使用POST。但现在既然支持了这么多API,用PUT方法上传文件也是可以实现的,而且语义上更合适。
PUT方法的特点是传输的实体部分是一个无结构的二进制数据,而POST方法则倾向于结构化的数据。上传文件这个行为本身就是无结构数据的传输(文件是一个整体,文件的内容与传输行为无关),所以使用PUT更合适。当然,上传文件这个行为不光是把文件丢到服务器上而已,可能还需要传递一些文件的相关信息,比如文件在客户端的文件名之类的,这在使用POST方法时很容易实现。其实使用PUT方法也不存在什么问题,这些额外信息完全可以用自定义的HTTP请求头来传输。
现代浏览器对文件操作的支持已经很丰富了,可以直接从FILE控件的 files 属性上获取到用户选中的文件对象,然后通过XHR对象的 send 方法发送到服务器,这非常方便。而且服务器端省去了对 multipart/form-data 的解析,实现起来更加容易。
使用PUT方法上传文件也存在一些需要解决的问题。根据PUT的语义,我们需要知道文件上传之后的URL(这个URL在文件上传前访问的话是404状态码),而不是像POST方法一样,把所有的上传都提交到同一个URL上。另外则是安全性的问题,并不是所有人都有上传的权限,比如某个资源属于某个用户,只有这个特定用户可以操作,这实现起来就有点麻烦(其实POST方法如果要实现这个的话也挺麻烦的,只是POST的麻烦被掩盖了)。对于这些问题,我觉得使用文件MD5作为URL就很容易解决。文件上传前在前端就可以计算出MD5,就可以得到上传后的URL,上传后文件也不会被篡改,权限问题也随之解决了。
其实对于PUT方法上传文件,我想到的远不止以上这些。只是我的语言比较贫乏,没办法把一堆关系松散的概念一下子描述出来。我打算先试着把这玩意儿先实现出来,证明一些想法的正确性后再做进一步说明。