在 hapijs 17.0 中上传个人资料图片

uploading profile pic in hapijs 17.0

我使用的是 hapijs 版本 17.0.1。我正在尝试在 hapijs 路由上使用 ajax 请求上传图像。这是我的 AJAX 上传个人资料图片的代码:

var image_file_input = document.getElementById("user_profile_upload");

image_file_input.onchange = function () {
    if(this.files != undefined)
    {
        if(this.files[0] != undefined)
        {
            var formData = tests.formdata ? new FormData() : null;
            if (tests.formdata)
            {
                //alert(file)
                formData.append('image_file', this.files[0]);
                formData.append('userId', user_id);
                formData.append('memberId', member_id);
            }
            $.ajax({
                url: "/v1/User/uploadUserPic",
                data: formData,
                type: "POST",
                dataType: "json",
                contentType: false,
                processData: false,
                contentType: "multipart/form-data",
                success: function(data){
                    console.log(data);
                    var errMsg = null;
                    var resData = null;
                    if(data.statusCode == 200)
                    {
                        resData = data.result;
                    }
                    else
                    {
                        alert(data.message)
                    }
                },
                error: function(error){
                    alert(error);
                }
            });
        }
    }
}

这是我的 Hapijs 路由代码:

    var uploadUserPic = {
        method: 'POST',
        path: '/v1/Module/uploadUserPic',
        config: {
            description: 'Update Image For User',
            tags: ['api', 'User'],
            auth: 'session',
            payload: {
                output: 'stream',
                parse: true,
                allow: 'multipart/form-data'
            },
            validate: {
                payload: {
                    userId : Joi.string().regex(/^[a-f\d]{24}$/i).required(),
                    memberId: Joi.string().required(),
                    image_file: Joi.object().required(),
                },
                failAction: FailCallBack
            }
        },
        handler: function (request, reply) {
            var resultData = null;
            var error = null;
            return new Promise(function (resolve) {
                var multiparty = require('multiparty');
                var fs = require('fs');
                var form = new multiparty.Form();
                form.parse(request.payload, function (err, fields, files) {
                    if(err)
                    {
                        error = err;
                        resolve();
                    }
                    else
                    {
                        var mkdirp = require('mkdirp');
                        var img_dir = "./files/users/";
                        mkdirp(img_dir, function (err) {
                            if (err)
                            {
                                error = err;
                                console.error(err);
                                resolve();
                            }
                            else
                            {
                                var oldpath = files.image_file.path;
                                var newpath = "./files/users/"+requestPayload.userId+".png";
                                fs.rename(oldpath, newpath, function (err) {
                                    if(err)
                                    {
                                        error = err;
                                    }
                                    resolve();
                                });
                            }
                        });
                    }
                });
            }).then(function (err, result) {
                if(err) return sendError(err);
                if(error) return sendError(error)
                return {
                    "statusCode": 200,
                    "success": true
                };
            });
        }
    }

上面的代码在行 form.parse(request.payload, function (err, fields, files) {});

上给出了以下错误 cannot read property 'content-length' of undefined

如果我做错了什么,请告诉我。如果我将 ajax 请求中的 url 替换为我在 php 中编写的另一个 url,那么它将完美运行。这意味着我的 hapijs/nodejs 代码有问题。

post Hapi.js 中有一篇很好的关于如何处理文件上传的文章(写于第 16 版)https://scotch.io/bar-talk/handling-file-uploads-with-hapi-js

由于您使用的是 payload.parse = true,我看不出您必须使用 multiparty 的具体原因。我有以下工作代码,可以将从客户端上传的文件(任何类型)保存到服务器上的上传目录中(请不要直接在生产中使用,因为没有完成卫生)

        {
            path: '/upload',
            method: 'POST',
            config: {
                payload: {
                    output: 'stream',
                    parse: true,
                    allow: 'multipart/form-data'
                },
                validate: {
                    payload: {
                        files: Joi.array().single()
                    }
                }
            },
            handler: function(request) {
                const p = request.payload, files = p.files
                if(files) {
                    console.log(`${files.length} files`)
                    files.forEach(async file => {
                        const filename= file.hapi.filename
                        console.log(`Saving ${filename} to ./uploads`)
                        const out = fs.createWriteStream(`./uploads/${filename}`)
                        await file.pipe(out)
                    })
                }
                return {result: 'ok'}
            }
        }

可以使用以下curl命令进行测试

curl http://localhost:8080/upload -F 'files=@/path/to/a/note.txt' -F 'files=@/path/to/test.png' -vvv

您的代码存在一些问题。首先在您的 $.ajax 调用中,您指定了 contentType 两次,虽然这不是语法错误,但这样编码是粗心的。其次,您的 .then() 块中的函数签名不正确。您正在混合 Promise 和回调的想法。我认为不会触发以下行

        if(err) return sendError(err);

最后一件小事,你说你使用的是 Hapi 17 但基于处理函数的签名

handler: function (request, reply) {
...

看来您还没有完全接受 Hapi17,因为新签名是

handler: function (request, h) {

这不仅仅是将 reply 重命名为 h