【问题标题】:Uploading an image in Laravel via Ajax通过 Ajax 在 Laravel 中上传图片
【发布时间】:2019-11-06 18:46:44
【问题描述】:

我正在尝试更新包含标题(文本)、正文(文本区域)和图像(文件)的“文章”。一切顺利,直到我尝试通过 ajax 实现上传。通过常规 Laravel 上传图像意味着效果很好,但是使用 ajax,我遇到了一些障碍。首先,它拒绝验证文件。其次,如果我在控制器方法中注释掉对文件的验证,它会很好地“排序”......但是然后检查$request->hasFile("image")根本不识别文件......所以改为写入db一个默认的(“ noimage.jpg”)。我的其他 ajax 函数运行良好,只有更新会导致问题。

这里是ajax函数:

function ajaksUpdate(){
let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
console.log("hitUpdate");
//console.log();

let updateForm = document.getElementById("updateForm");

let urlId = window.location.href;
let getaArticleId = urlId.lastIndexOf("/");
let articleId = urlId.substring(getaArticleId+1, urlId.length);

let updateFormElements = {};
updateFormElements.title = updateForm.elements[3].value;
updateFormElements.body = CKEDITOR.instances.ckeditor.getData();//Ovo trece po redu je id polja sa ckeditorom.
updateFormElements.image = updateForm.elements[5].files[0];

//console.log();
/*var myformData = new FormData();        
myformData.append('title', updateFormElements.title);
myformData.append('body', updateFormElements.body);
myformData.append('image', updateFormElements.image);
let formData = $('#updateForm').serializeArray();
console.log(updateFormElements);*/
console.log("******");
/*for (var [key, value] of myformData.entries()) { 
    console.log(key, value);
}*/

$.ajax({

    url: '/updateAjax/'+articleId,
    enctype: 'multipart/form-data',
    type: 'POST',
    data: {_token: token , message: "bravo", articleId: articleId, title: updateFormElements.title, body: updateFormElements.body,image:updateFormElements.image},
    dataType: 'JSON',
    /*cache: false,
    contentType: false,
    processData: false,*/
    success: (response) => { 
        console.log("success");
        console.log(response);
    },
    error: (response) => {
        console.log("error");
        console.log(response);
    }
}); 

}

这里是控制器方法:

public function ajaxUpdate(Request $request)
    {

        if($request->ajax()){

            $article = Article::find($request->articleId);

            $validator = \Validator::make($request->all(), [
                "title" => "required",
                "body" => "required",
                'image' => 'image|nullable|max:1999'/*If commented, validation passes.*/
            ]);

            if ($validator->passes()){/*If validation passes, it cannot find 'image'*/
                $hasImage = false;
                //Handle file upload
                if($request->hasFile("image")){
                    $filenameWithExt = $request->file("image")->getClientOriginalName();
                    $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME);
                    $extension = $request->file("image")->getClientOriginalExtension();
                    $fileNameToStore = $filename."_".time().".".$extension;
                    $path = $request->file("image")->storeAs("public/images", $fileNameToStore);
                }
                else{
                    $fileNameToStore = "noimage.jpg";
                }

                $article->title = $request->input("title");
                $article->body = $request->input("body");
                //$article->user_id = auth()->user()->id;
                $article->image = $fileNameToStore;
                $article->save();


                $response = array(
                    'status' => 'success',
                    'msg' => "Hello!",
                    "request" => $request->all(),
                    "passesValidation" => true,
                    "article" => $article,
                    "hasImage" => $hasImage,
                );

                return response()->json($response);

            }
            else{

                $response = array(
                    'status' => 'success',
                    'msg' => "Hello!",
                    "request" => $request->all(),
                    "passesValidation" => false,
                );
                return response()->json($response);

            }

        }

    }

编辑1:

如果控制器中的验证(图像)没有被注释掉,它会显示如下字符串:“C:\fakepath\855d671944d2c143ba672010acd04437.jpg”。 Json if 没有被注释掉:

{
    msg: "Hello!"
    passesValidation: false
    request:
    articleId: "3"
    body: "posttext"
    image: "C:\fakepath\855d671944d2c143ba672010acd04437.jpg"
    message: "bravo"
    title: "Post1"
    _token: "ZVZ9NDNOcMdgoJgvzYhR9LmrPfh7RfMiM1QJVk9v"
    __proto__: Object
    status: "success"
    __proto__: Object
}

如果注释掉,json 看起来像这样:

{
    article: {id: 3, title: "Post1", body: "<p><em>Lorem ipsum</em><strong> </strong>dolor sit…ctum. Duis feugiat facilisis lectus a cursus.</p>", created_at: "2019-06-18 00:23:25", updated_at: "2019-06-25 00:18:37", …}
    hasImage: false
    msg: "Hello!"
    passesValidation: true
    request:
    articleId: "3"
    body: "posttext"
    image: "C:\fakepath\855d671944d2c143ba672010acd04437.jpg"
    message: "bravo"
    title: "Post1"
    _token: "ZVZ9NDNOcMdgoJgvzYhR9LmrPfh7RfMiM1QJVk9v"
    __proto__: Object
    status: "success"
    __proto__: Object
}

编辑2:

我也试过了:

let formData = new FormData();
formData.append("title", updateFormElements.title);
formData.append("body", updateFormElements.body);
formData.append("image", updateFormElements.image); 

并插入并发送它。它抛出“非法调用......”。无论出于何种原因,当我 console.log(formData) 它时,formData 对象是空的。

编辑3: 即使我在 ajax 调用中添加 processData: false。但随后它会抛出 419 错误...

编辑4:

我不知道它是否会有所帮助,但是我的表单处于模态,没有提交按钮,并且带有 ajaksUpdate() 功能的按钮是提交/更新的按钮,它在表单之外。我正在使用 put 方法进行更新,也获得了模态形式的 csrf。

这是我的表单/模态的图像:

编辑5:

根据@pal 的要求: 我的 html 是在加载文档时调用的另一个函数中动态形成的,在布局刀片中:

function ajaksShow(){
    let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
    console.log("hit");
    //var n = str.lastIndexOf("planet");
    let urlId = window.location.href;
    let getaArticleId = urlId.lastIndexOf("/");
    let articleId = urlId.substring(getaArticleId+1, urlId.length);
    console.log(articleId);

    $.ajax({
        url: '/showAjax',
        type: 'POST',
        data: {_token: token , message: "bravo", articleId: articleId},
        dataType: 'JSON',
        success: (response) => { 
            console.log("success");
            console.log(response);
            let body = "";
            let imageStyle = ";height: 435px; background-position: center top; background-attachment: fixed; background-repeat: no-repeat;background-size:cover;";

            let img = response.article.image;
            let find = " ";
            let rep = new RegExp(find, 'g');
            img = img.replace(rep, "%20"); // class="alert alert-danger"
            let mymodalDelete = "<div class='modal' id='myModalDelete'><div class='modal-dialog'><div class='modal-content'><div class='modal-header'><h4 class='modal-title'>Do you really want to delete this article?</h4><button type='button' class='close' data-dismiss='modal'>&times;</button></div><div class='modal-body'>deleting ...</div><div class='modal-footer'><button class='btn btn-outline-danger' style='position: absolute;left:0px; margin-left: 1rem;' onclick='ajaksDelete(this)'>Delete</button><button type='button' class='btn btn-danger' data-dismiss='modal'>Close</button></div></div></div></div>";

            let updateForm = "<form method='POST' id='updateForm' enctype='multipart/form-data'><input type='hidden' name='_method' value='PUT'><input type='hidden' name='_token' value='"+token+"'><input id='' type='hidden' name='article_id' value='"+response.article.id+"' /><div class='form-group'><label class='label' for='title'>Title</label><input type='text' class='form-control' name='title' placeholder='Title' value='"+response.article.title+"' required></div><div class='form-group'><label for='body'>Body</label><textarea class='form-control' id='ckeditor' name='body' placeholder='Body' required>"+response.article.body+"</textarea></div><div class='form-group'><input type='file' name='image' id='image'></div></form>";
            let mymodalUpdate = "<div class='modal' id='myModalUpdate'><div class='modal-dialog'><div class='modal-content'><div class='modal-header'><h4 class='modal-title'>Do you really want to update this article?</h4><button type='button' class='close' data-dismiss='modal'>&times;</button></div><div class='modal-body'>"+updateForm+"</div><div class='modal-footer'><button class='btn btn-outline-success' style='position: absolute;left:0px; margin-left: 1rem;' onclick='ajaksUpdate()'>Update</button><button type='button' class='btn btn-info' data-dismiss='modal'>Close</button></div></div></div></div>";

            let imageUrl = "/storage/images/"+img;
            let html = "<a href='/list' class='btn btn-outline-info btn-sm'>Go Back</a><div class='nextPrev'><a href='/list/"+response.prev+"' class='btn btn-outline-success'><i class='fas fa-arrow-left'></i></a><a href='/list/"+response.next+"' class='btn btn-outline-info'><i class='fas fa-arrow-right'></i></a></div><br><br><div id='single-kv' style='background-image: url("+imageUrl+")"+imageStyle+";background-color: red !important;'></div><div id='single-intro'><div id='single-intro-wrap'><h1> "+response.article.title+"</h1>";

                if(response.article.body.length > 400){
                    body = response.article.body.substring(0, 400)+"<a id='readMore' href='/list/"+response.article.id+"'>...Read more</a>";
                }
                else{
                    body = response.article.body;
                }

                html += body;

                html += "<div class='comment-time excerpt-details' style='margin-bottom: 20px; font-size: 14px;'><a href='#gotoprofil'> "+response.user.name+" </a> - "+response.article.created_at+"</div><button id='update' class='btn btn-outline-info btn-sm float-left' data-toggle='modal' data-target='#myModalUpdate' onclick='getCkEditor()'>Update</button><button class='btn btn-outline-danger btn-sm float-right' data-toggle='modal' data-target='#myModalDelete'>Delete</button></div></div><br><hr style='color:whitesmoke; width: 50%;'><div id='single-body'><div id='single-content'>"+response.article.body+"</div></div>"+mymodalDelete+mymodalUpdate;


            if(document.getElementById("maine")){

                document.getElementById("maine").innerHTML = html;

            }

        },
        error: (response) => {
            console.log("error");
            console.log(response);
        }
    }); 

}

Form 是 updateForm 变量,激活它的按钮位于 mymodalUpdate 变量中,它调用函数 ajaksUpdate()。 updateForm 也被链接在 mymodalUpdate 中,每边有两个加号。

编辑6: 我也试过了:

let formData = $('#updateForm').serializeArray();
console.log(formData);

但它只显示 csrf、隐藏方法 put 字段、token、title 和 body 字段。没有文件字段?

编辑7:

这里有两张(我希望)有助于说明我的观点的图片:

第二个

编辑8:

有人说是csrf不匹配,419错误,所以建议暂时禁用csrf看看是什么,下面是图片:

记录和中间件:

并记录和控制器方法:

更新了更改 ajax 功能。如果我添加到 ajax 调用

cache: false,
contentType: false,
processData: false,

然后它显示:“POST http://articleapp.test/updateAjax/3 419(未知状态)”错误。如果注释掉这三行,则显示:“Uncaught TypeError: Illegal invocation 在添加...”错误。我尝试了一切。csrf不是因为我尝试禁用,它发送空白请求。

最终编辑: 我不知道我做了什么,但文件上传工作。 这是ajax函数:

function ajaksUpdate(){
    let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
    console.log("hitUpdate");
    //console.log();

    let updateForm = document.getElementById("updateForm");

    let urlId = window.location.href;
    let getaArticleId = urlId.lastIndexOf("/");
    let articleId = urlId.substring(getaArticleId+1, urlId.length);

    let updateFormElements = {};
    updateFormElements.title = updateForm.elements[3].value;
    updateFormElements.body = CKEDITOR.instances.ckeditor.getData();//Ovo trece po redu je id polja sa ckeditorom.
    updateFormElements.image = updateForm.elements[5].files[0];

    let imginp = document.getElementById("imagex").files;
    //console.log(imginp);

    var myformData = new FormData();        
    myformData.append('title', updateFormElements.title);
    myformData.append('body', updateFormElements.body);
    myformData.append('image', updateFormElements.image);
    myformData.append('_token', token);
    myformData.append('articleId', articleId);
    //let formData = $('#updateForm').serializeArray();

    console.log("******");
    for (var [key, value] of myformData.entries()) { 
        console.log(key, value);
    }
    console.log("======");

    $.ajax({

        url: '/updateAjax/'+articleId,
        enctype: 'multipart/form-data',
        type: 'POST',
        data: myformData,
        dataType: 'JSON',
        cache: false,
        contentType: false,
        processData: false,
        success: (response) => { 
            console.log("success");
            console.log(response);
        },
        error: (response) => {
            console.log("error");
            console.log(response);
        }
    }); 

}

这里是控制器方法:

public function ajaxUpdate(Request $request)
    {

        if($request->ajax()){

            $article = Article::find($request->articleId);

            $validator = \Validator::make($request->all(), [
                "title" => "required",
                "body" => "required",
                'image' => 'image|nullable|max:1999'
            ]);

            if ($validator->passes()){
                $hasImage = false;
                //Handle file upload
                if($request->hasFile("image")){
                    $filenameWithExt = $request->file("image")->getClientOriginalName();
                    $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME);
                    $extension = $request->file("image")->getClientOriginalExtension();
                    $fileNameToStore = $filename."_".time().".".$extension;
                    $path = $request->file("image")->storeAs("public/images", $fileNameToStore);
                }
                else{
                    $fileNameToStore = "noimage.jpg";
                }

                $article->title = $request->input("title");
                $article->body = $request->input("body");
                //$article->user_id = auth()->user()->id;
                $article->image = $fileNameToStore;
                $article->save();

                $response = array(
                    'status' => 'success',
                    'msg' => "Hello!",
                    "request" => $request->all(),
                    "passesValidation" => true,
                    "article" => $article,
                    "hasImage" => $hasImage,
                );

                return response()->json($response);

            }
            else{

                $response = array(
                    'status' => 'success',
                    'msg' => "Hello!",
                    "request" => $request->all(),
                    "passesValidation" => false,
                );
                return response()->json($response);

            }

        }

    }

只是想留在这里留给后人,问问别人:你有没有遇到过奇迹般解决的问题,但你对解决方案一无所知?

【问题讨论】:

标签: ajax laravel


【解决方案1】:

看来您正在上传图像的本地路径,而不是 Ajax 方法中的图像本身。阅读this part of MDN documentation我意识到你可能会这样写:

updateFormElements.image = updateForm.elements[5].files[0];

【讨论】:

  • 它显示一个错误:“Uncaught TypeError: Illegal invocation at add (app.js:14882) at buildParams (app.js:14869) at buildParams (app.js:14863) at Function.jQuery .param (app.js:14906) at Function.ajax (app.js:15498) at ajaksUpdate (skripta.js:254) at HTMLButtonElement.onclick (3:1)"
  • 它有效。它获取文件集合: File {name: "855d671944d2c143ba672010acd04437.jpg", lastModified: 1446990238486, lastModifiedDate: Sun Nov 08 2015 14:43:58 GMT+0100 (Central European Standard Time), webkitRelativePath: "", size: …123865, } 但仍然无法上传。抛出我之前所说的错误。
【解决方案2】:

不是这个

let formData = new FormData();
formData.append("title", updateFormElements.title);
formData.append("body", updateFormElements.body);
formData.append("image", updateFormElements.image); 

使用这个

var formData = new FormData(this);

完整源代码如下,因为您是动态生成的,如果直接给出点击事件,请使用事件绑定: 请检查一下 event binding

只需像这样给出按钮: 提交 from 外面的按钮可以是 from 的一部分,看看这个button outside form

<script>

    $(document).ready(function (e) {

      $('#updateBtn').on('submit',(function(e) {

        $.ajaxSetup({

          headers: {

             'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')

             }

            });

         e.preventDefault();

          var formData = new FormData(this);

           $.ajax({

                 type:'POST',

                  url: "{{ url('save-image')}}",

                  data:formData,

                  success:function(data){ },

                  error: function(data){}

            });

          }));

         });

【讨论】:

  • 试过了。不起作用,它只是出于某种原因弄乱了网址。你能举出包含我的代码的例子吗?
  • 请同时提供您的html
  • 根据要求提供 html。
  • 你不能把更新按钮放在里面吗?也请检查编辑的asnwer
  • 添加按钮以形成自身,阻止默认行为。不得不添加我的网址。现在说:“此路由不支持 PUT 方法。支持的方法:GET、HEAD。”我需要放,因为我正在更新。
【解决方案3】:

要使用 ajax 上传文件,试试这个:

var fileData = $('#id_of_file').prop('files')[0];

var formData = new FormData();  // Create formdata object
formData.append('fileData', fileData);  // append key: value pair in it
formData.append('key1', value1);
formData.append('key2', value2);

并在 ajax 中使用它,例如:

$.ajax({
    url: $('meta[name="route"]').attr('content') + '/ur_route',
    method: 'post',
    data: formData,
    contentType : false,
    processData : false,
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    },
    success: function(response){
        // do whatever you want
    }
});

在服务器端(控制器),您将使用fileData 索引获取文件。

【讨论】:

    猜你喜欢
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多