Vue.js - 当标头中使用 multipart/form-data 时,axios 中的文件上传验证失败

Posted

技术标签:

【中文标题】Vue.js - 当标头中使用 multipart/form-data 时,axios 中的文件上传验证失败【英文标题】:Vue.js - validation fails for file upload in axios when multipart/form-data used in header 【发布时间】:2020-04-15 14:44:01 【问题描述】:

我正在构建一个 Laravel+Vue.js SPA(单页应用程序),使用 BootstrapVue、VeeValidate 和 axios 作为 HTTP 客户端。

在 axios 内部,当我在 headers 中使用 multipart/form-data; boundary=$uploadForm._boundary 作为 Content-Type 然后 Laravel Controller 方法中的所有验证都失败

但如果我在header 中使用'content-type': 'multipart/form-data',则验证工作除了file 输入字段。在 Laravel 控制器方法中,file 字段变为空。

这发生在组件EditProfile.vue 中。里面的内容是:

<template>
<ValidationObserver ref="form" v-slot=" passes ">

        <div id="registration_form">

            <div id="form_title" class="text-center">Edit Your Profile</div>
            <div v-html="result" class="result text-center"></div>


            <b-form name="uploadForm" @submit.prevent="passes(onSubmit)" @reset="resetForm"  enctype="multipart/form-data">


                <ValidationProvider vid="name" rules="required|min:2" name="name" v-slot=" valid, errors ">
                    <b-form-group
                            label="User Name:"
                            label-for="exampleInput1"

                    >
                        <b-form-input
                                type="text"
                                disable-leading-trailing-space
                                v-model="name"
                                plaintext
                                :state="errors[0] ? false : (valid ? true : null)"
                                placeholder="Enter your name"
                        ></b-form-input>
                        <b-form-invalid-feedback id="inputLiveFeedback"> errors[0] </b-form-invalid-feedback>
                    </b-form-group>
                </ValidationProvider>



                <ValidationProvider vid="photo" rules="required" name="photo" v-slot=" valid, errors ">
                    <b-form-group
                            label="Photo:"
                            label-for="exampleInput1"
                    >


                        <b-form-file

                                accept="image/x-png,image/gif,image/jpeg"
                                v-model="file"
                                :state="Boolean(file)"
                                placeholder="Choose a file or drop it here..."
                                drop-placeholder="Drop file here..."
                                @change="onFileChange" enctype="multipart/form-data"
                        ></b-form-file>
                        <b-form-invalid-feedback id="inputLiveFeedback"> errors[0] </b-form-invalid-feedback>
                        <div class="mt-3">Selected file:  file ? file.name : '' </div>

                        <!-- Plain mode -->
                        <!--<b-form-file v-model="file2" class="mt-3" plain></b-form-file>
                        <div class="mt-3">Selected file:  file2 ? file2.name : '' </div>-->

                        <div id="preview">
                            <img v-if="url" :src="url" />
                        </div>

                    </b-form-group>
                </ValidationProvider>





                <b-button type="submit" variant="primary">Submit</b-button>
                <b-button type="reset" variant="danger">Reset</b-button>
            </b-form>

        </div><!-- end of id registration_form-->
    </ValidationObserver>
</template>

在 JS 部分,我有:

<script>

  
    import  ValidationObserver, ValidationProvider  from "vee-validate";

     export default 
        name: "EditProfile",
        props: 

        ,

        components: 
            ValidationObserver,
            ValidationProvider
           

        ,
        data: () => (

            name: "",
            photo:"",
            file:"",
            url:"",  
            result:''

        ),

        methods: 
            onFileChange(e) 
                this.file = e.target.files[0];
                this.url = URL.createObjectURL(this.file);
            ,
        onSubmit() 
                console.log("Form submitted yay!");


                this.result='<span class="wait">Please wait ...</span>';

                axios.post('/update_profile_now',
                    
                       name: this.name,
                       photo:this.file

                    , // the data to post
                    


                        headers: 
      
                            //Accept: 'application/json',

                           'Content-Type':  `multipart/form-data; boundary=$uploadForm._boundary`
                            
                        



                    )
                    .then(response => 
      
                        if(response.data.success)

                            this.result='<span class="succes">Registration completed !!</span>';
                        else

                            this.$refs.form.setErrors(response.data.errors);

                            this.result='<span class="error">Invalid data !!</span>';
                        


      

                    )
                    .catch(error => 

                        if(typeof error !=="undefined")

                            console.log(error);
                        

                    );

                //    .finally(() => this.loading = false)
            ,
            resetForm() 
                this.name = "";
      
                this.result='';

                requestAnimationFrame(() => 
                    this.$refs.form.reset();
                );
            
        
    ;

</script>

在相应的 Laravel 控制器方法中我有:

 public function update_profile_now(Request $request)
    

        
        $rules = array(

            'name' => 'required | min:4',
            'photo'=> 'image|mimes:jpeg,png,jpg|max:2048'
        );

        $validator = Validator::make(Input::all(), $rules);

        // Validate the input and return correct response
        if ($validator->fails())
        
            return Response::json(array(
                'success' => false,
                'errors' => $validator->getMessageBag()->toArray()

            ), 200); 
        

        //file uploading code goes here 

        return Response::json(array('success' => true), 200);




   

我想要的是其中包含file 输入的表单将被提交,然后在文件上传和其他工作之后从该方法发送 JSON 响应。

那么正确的标题应该是什么,还是我需要采取任何其他方式?

【问题讨论】:

您正在尝试将this.file 发布为json 有效负载,但使用multipart MIME 类型.. 我想它不会这样工作.. 看看@ 987654323@ 并将name 字段也作为多部分字段(而不是json)传递 ' 将名称字段也作为多部分字段(而不是 json)传递' - 你是什么意思?该怎么做? 好吧,我假设您需要为此使用FormData#append.. 让我试试这个 你说得对,好像是。 【参考方案1】:

我想使用FormData API 会起作用。

下面是一些例子:

How to post a file from a form with Axios axios post request to send form data

【讨论】:

【参考方案2】:

我建议在提交表单后使用VeeValidation 来验证您的表单。

这是非常简单和最甜蜜的验证方法。

您可以从这里安装它。 VeeValidation Link

【讨论】:

以上是关于Vue.js - 当标头中使用 multipart/form-data 时,axios 中的文件上传验证失败的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中使用 multipart/form-data 处理没有 Content-Disposition 标头的 POST

为啥我的“multipart/form-data”标头不能阻止发送预检 (OPTIONS) 请求?

Node.js、Vue.js 和 Passport.js。 .isAuthenticated() 总是返回 false? Axios 标头可能吗?

由于不允许的预检标头,Vue.js 前端与 Flask 后端 CORS 问题交互

批处理请求必须具有“Content-Type”标头/“multipart/mixed”作为媒体类型

已解决 - CORS、OPTIONS 和 PreFlight 问题 在 Vue.js 中使用 Axios 使用 REST API