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

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

前言

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

文件上传解决方案

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

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

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

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来解决。ajax

文件上传解决方案--fetch

Fetch是浏览器的原生API,能够像Ajax那样请求后台接口。不过由于它是基于Promise的,因此不支持Promise的浏览器则没法使用该方法。闲话不说,如何经过fetch来实现上传?express

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等等)。不过这种方法有个致命的问题,那就是会有跨域问题。对于这个问题,笔者会在博客末尾提供相关解决方案。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模块。app

跨域管理

笔者经常使用的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下来耍耍。固然里面还包含了下一篇文件下载的代码,你们能够也顺带看看。

相关文章
相关标签/搜索