【问题标题】:"Multipart/form-data" is not woking in React-redux form upload“Multipart/form-data”在 React-redux 表单上传中不起作用
【发布时间】:2020-07-21 17:20:31
【问题描述】:

我在从输入类型file 获取文件上传值时遇到了一些问题。 我得到的是文件路径名,但我想获取将其上传到 cloudinary 的整个路径。 当我从 postman form-data 发送数据时,它工作正常,但通过前端我没有得到意想不到的结果。

有什么建议我可以在这里改变吗?

//博客.js

class BlogModal extends Component {
    state = {
        modal: false,
        blog_short_desc: '',
        blog_image_url: '',
        blog_by_author: ''
    }

    static propTypes = {
        auth: PropTypes.object.isRequired
    }

    onChange = (e) => {
        this.setState({ [e.target.name] : e.target.value });
    }

    onFileChange = (e) => {
        this.setState({ [e.target.name] : e.target.files[0] });
    }

    onSubmit = (e) => {
        e.preventDefault();

        const FileName = this.state.blog_image_url ;
        
        const newBlog = {
            blog_short_desc: this.state.blog_short_desc,
            blog_image_url: FileName,
            blog_by_author: this.props.auth["user"].name
        }
        console.log(newBlog);
        //Add item via addItem action
        this.props.addBlog(newBlog);
        alert("Blog added successfully!");
    }
    render(){
       
        return(
            <div>
                <Form onSubmit ={this.onSubmit } enctype="multipart/form-data">
                    <FormGroup>
                        <Label for="blogHeading">Blog Heading</Label>
                        <Input type="text" name="blog_short_desc" id="blogHeading" placeholder="Add one liner"
                        onChange={this.onChange} required/>

                        <Label for="blogImageURl">Image Url</Label>
                        <Input type="file" name="blog_image_url" id="blogImageURl" placeholder="Add image url "
                        onChange={this.onFileChange} />

                        <Button color="dark" style={{marginTop: '2rem'}} block>Add blog</Button>
                    </FormGroup>
                </Form>
            </div>
        )
    }
}

const mapStateToProps = state => ({
    resume: state.resume,
    auth: state.auth
})

export default connect(mapStateToProps, { addBlog })(BlogModal);

//动作

export const addBlog = blog => (dispatch, getState) => {
    
    const config = {
        headers: {
            Accept: 'application/json',
            'Content-Type': 'multipart/form-data',
        }
    }
   axios
   .post('/api/blogs', blog, tokenConfig(getState), config)
   .then(res => 
    dispatch({
        type: types.ADD_BLOG,
        payload: res.data
    })).catch (err => dispatch (returnErrors(err.response.data, err.response.status)));
    
};

//路由器

router.post('/', upload.single('blog_image_url'), async (req, res, next) => {

    try {
    const result = await cloudinary.uploader.upload(req.file.path);
    const newBlog = new Blog({
        blog_short_desc: req.body.blog_short_desc,
        blog_name: req.body.blog_name,
        blog_desc: req.body.blog_desc,
        blog_image_url: result.secure_url,
        blog_by_author: req.body.blog_by_author

    });

    await newBlog.save().then(blogs => res.json(blogs));
    next();
    } catch (error) {
        next(error);
    }
});

//令牌配置

// setup config/headers and token
export const tokenConfig = getState => {
        //Get token from local storage
        const token = getState().auth.token;

        // headers
        const config = {
            headers: {
                "content-type": "application/json"
            }
        }
    
        //if token then add to headers
    
        if(token) {
            config.headers['x-auth-token'] = token;
        }
    return config;
};

//网络面板中的当前值

blog_by_author: "Tanmoy Sarkar"
blog_desc: "fddgdfgfd"
blog_image_url: {}
blog_name: "sirirrrheyyy siri"
blog_short_desc: "How I learned the Ups & downs"

//期望值(现在通过邮递员通过表单数据设置)

{ asset_id: '9f271dc05712daf92b05702d95549c5a',
[0]   public_id: 'bia1qqug7bkrz1n29wai',
[0]   version: 1595352697,
[0]   version_id: '632b918f3b664cee4661e7c124786e8c',
[0]   signature: '981e2cc7c5e90a7cf8adf517cb79513132737f60',
[0]   width: 675,
[0]   height: 505,
[0]   format: 'jpg',
[0]   resource_type: 'image',
[0]   created_at: '2020-07-21T17:31:37Z',
[0]   tags: [],
[0]   bytes: 211385,
[0]   type: 'upload',
[0]   etag: '269901e75a4d992a40c2507e884b5a2b',
[0]   placeholder: false,
[0]   url:
[0]    'http://res.cloudinary.com/tammycloudinary/image/upload/v1595352697/bia1qqug7bkrz1n29wai.jpg',
[0]   secure_url:
[0]    'https://res.cloudinary.com/tammycloudinary/image/upload/v1595352697/bia1qqug7bkrz1n29wai.jpg',
[0]   original_filename: 'tmp-1-1595352688726' }

//来自网络面板

//内容类型仍然是application/json,文件对象为空

//使用邮递员表单数据

【问题讨论】:

  • e.target.files[0]
  • 嗨@epascarello 我已经尝试过了,但它返回 VM11115:1 Uncaught TypeError: Cannot read property '0' of undefined
  • 表示它不是文件输入。您将不得不为文本和文件创建不同的更改事件处理程序。
  • 对我当前的代码有什么建议吗?
  • @epascarello 你的建议奏效了...

标签: javascript reactjs rest redux axios


【解决方案1】:

所以,我猜你正在使用 multer,如果我是对的,你必须使用 req.file 而不是 req.files.blog_image_url,因为你将它定义为 single 文件,在 multer 文档中有一个例子:

app.post('/profile', upload.single('avatar'), function (req, res, next) {
  // req.file is the `avatar` file
  // req.body will hold the text fields, if there were any
})

另外,您要确保请求具有 Content-Type 标头,其值为 “多部分/表单数据”。

axios 接受配置对象作为第三个参数,不支持第四个参数。可能你在tokenConfig(getState) 中返回一个对象,其中包含一个header 对象,所以你必须将它与:

headers: {
    Accept: 'application/json',
    'Content-Type': 'multipart/form-data',
}

【讨论】:

  • 嗨,stackedQ,感谢您的宝贵时间。我试图在我的 action.js 中设置content-Type: multipart/form-data,但我仍然使用application/json。这里有任何建议。我也更新了我的代码。
  • tokenConfig 中发生了什么?
  • 整个项目定义为application/json。我已经更新了我的代码。
  • 这解决了我的多部分问题。但我仍然收到blog_by_author: "Tanmoy Sarkar" blog_desc: "sfdsfdsfsf" blog_image_url: {} blog_name: "sirirrrheyyy " blog_short_desc: "Hey " 的文件,对此有什么建议吗?
猜你喜欢
  • 2012-03-03
  • 2018-10-05
  • 1970-01-01
  • 2023-03-30
  • 2019-01-12
  • 1970-01-01
  • 2020-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多