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

[ 一起学React系列 -- 8 ] React中的文件上传

终于抽出时间来继续更新自己的博客,最近忙得够呛...
对于该系列博客不知道大家有没有这样的看法,对于React常见的基础东西并没有过多或者详细列出,感觉有点不符合系列标题。的确,笔者一开始也想把React基础从头到尾列一边,但是想想看没这个必要,因为这种基础教程在网上多如牛毛,再写岂不是重复造轮子,所以笔者就挑一些相对“偏僻”但是肯定会用到的东西拿出来分享。

前言

本期的主题是在React中如何实现文件上传。文件上传这个功能在实际开发过程中用的地方相对较多,当然还有很多花里胡哨的解决方案,不过万变不离其宗再复杂的解决方案也离不开最基础的技术,所以笔者将文件上传这一块详细整理了一下并且做了demo供大家参考学习。

文件上传解决方案

目前比较主流的解决方案就是form表单fetch(或者axios)form表单+fetch来实现。对于第二位而言,笔者本着能用原生就用原生的原则就没有使用axios模块。那么下面就一一开始分享。

文件上传解决方案--form表单

利用表单组件进行文件上传是远古时期就一直在用的方法而且还真经久不衰,厉害了。利用form表单的enctype属性可以把表单提交的对象设置为多媒体资源,然后通过inuput:file就可以实现文件上传的功能,例子如下:

import React, {Component} from 'react'

class FormUploadOnly extends Component {
    render() {
        return (
            <div>
                <form action="http://127.0.0.1:3001/file/upload" method="post" enctype="multipart/form-data">
                    <input type="file" name='file'/>
                    <input type="submit" value="上传"/>
                </form>
            </div>
        )
    }
}

export default FormUploadOnly;

这个solution相对便捷有效而且还不用考虑跨域的问题,毕竟我们上传的文件终究还是要访问API接口;不过这种方法还有一个不方便的地方,就是form表单会默认跳转也就是会在浏览器访问你所提交文件的那个接口,这个行为处理起来很麻烦。这个问题笔者推荐通过一个iframe来解决。

文件上传解决方案--fetch

Fetch是浏览器的原生API,可以像Ajax那样请求后台接口。不过因为它是基于Promise的,所以不支持Promise的浏览器则无法使用该方法。闲话不说,如何通过fetch来实现上传?

import React, {Component} from 'react';

class FetchUpload extends Component {
    constructor(props) {
        super(props);
        this.fileInput = React.createRef();
    }

    upload = () => {
        const data = new FormData();
        data.append('file', this.fileInput.current.files[0]);  //相当于 input:file 中的name属性
        fetch('http://127.0.0.1:3001/file/upload', {
            method: 'POST',
            body: data
        }).then(response => console.log(response))
    };
    render() {
        return (
            <div>
                <input type="file" name='file' ref={this.fileInput}/>
                <input type="button" value="上传" onClick={this.upload}/>
            </div>
        )
    }
}
export default FetchUpload;

这个方法比较投机取巧,就是将input:type中的数据append到FormData中,FormData会将数据编译成键值对,这样可以被fetch发送至后台(不仅仅限于fetch,也可以是ajax或者axios等等)。不过这种方法有个致命的问题,那就是会有跨域问题。对于这个问题,笔者会在博客末尾提供相关解决方案。

文件上传解决方案--fetch+form

这个方案看小标题和前面的内容,相信大家都能猜到是什么样子了。下面直接上代码:

import React, {Component} from 'react'

class FormUpload extends Component {
    submit = (e) => {
        e.preventDefault();
        let formData = new FormData(e.target);
        fetch('http://127.0.0.1:3001/file/upload', {
            method: 'POST',
            body: formData //自动将input:file的name属性与文件对象组合成键值对
        }).then(response => console.log(response))
    };

    render() {
        return (
            <div>
                <form onSubmit={this.submit}>
                    <input type="file" name='file'/>
                    <input type="submit" value="上传"/>
                </form>
            </div>
        )
    }
}

export default FormUpload;

总的来说,这个方法和第二中方法在原理上是相同的,只是获取的文件数据不是直接从input:type中获取的,而是从form的提交事件中获取的,其他的没什么变化,所以也会遇到跨域的问题。

后台组成

该博客的demo后台是express写的,所以不管是跨域管理还是接收并保存文件都是基于Node模块。

跨域管理

笔者常用的Node服务跨域解决方案是第三方库cors。当然cors除了是这个第三方库的名字,也有比较重要的W3C标准,它对解决浏览器跨域问题起到重要的作用,不过该博文的重点不在这所以不作赘述,相关的使用方法都在文末的demo里,有兴趣的朋友可以尝试用用,真的很high!

接收并保存文件

因为express自身的request对象不包含上传过来的文件对象,所以必须要用到第三方库multer。负责处理multipart/form-data 类型的表单数据和保存相关资源的作用。

小提示

利用multer初始化一个upload中间件对象时候需要指定一个“标志符”,比如:

let upload = multer({storage: storage}).single('file');

这里的标识符是file,对应前面代码中的:

<input type=" file" name=' file'/>

data.append(' file', this.fileInput.current.files[0])

这是一个不算大的坑,所以大家使用时候多多关注。

最后笔者奉上准备好的demo,有兴趣的话可以download下来耍耍。当然里面还包含了下一篇文件下载的代码,大家可以也顺带看看。

相关文章:

  • PhpStudy的安装及使用教程
  • [PHP] 算法-顺时针打印矩阵的PHP实现
  • Java集合-HashMap扰动函数
  • Django-jet自定义菜单
  • 解决org.apache.hadoop.hbase.MasterNotRunningException
  • Vue CLI 3开发中屏蔽烦人的EsLint错误
  • 搞定所有的跨域请求问题: jsonp CORS
  • 开源运维管理平台(ows) damo版本源码发布
  • 精彩回顾 | 阿里云APM城市技术行·深圳站
  • ballerina 学习 三十一 扩展开发(二)
  • ES7 之 Async/await 的使用(改进 Promise 链式操作)
  • LAMP+Postfix+Dovecot+Postfixadmin搭建邮件管理系统(三)
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • webpack 4.x一起学习(二)
  • String类的常用方法详解
  • JavaScript设计模式系列一:工厂模式
  • LeetCode算法系列_0891_子序列宽度之和
  • Linux链接文件
  • linux学习笔记
  • MQ框架的比较
  • React中的“虫洞”——Context
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 百度地图API标注+时间轴组件
  • 强力优化Rancher k8s中国区的使用体验
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 线性表及其算法(java实现)
  • 异常机制详解
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • ​HTTP与HTTPS:网络通信的安全卫士
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (原創) 系統分析和系統設計有什麼差別? (OO)
  • (转)jdk与jre的区别
  • (转)甲方乙方——赵民谈找工作
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • ..回顾17,展望18
  • .NET : 在VS2008中计算代码度量值
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .NET 使用 XPath 来读写 XML 文件
  • .net 提取注释生成API文档 帮助文档
  • .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)...
  • .Net环境下的缓存技术介绍
  • .NET框架
  • .NET性能优化(文摘)
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • [Android Pro] listView和GridView的item设置的高度和宽度不起作用
  • [android] 天气app布局练习