关于Nodejs图片保存的问题,纠结了好久急求大神解答

关于Nodejs图片保存的问题,纠结了好久急求大神解答

我想用Node实现图片文件的存储,然后通过IOS客户端上传。在网上找了好久,一直没能解决问题

app.post('/avatar', function(req, res) {
        console.log(req);
        if(!(req.query.username)) {
            return res.json({
                code: 0,
                msg: '参数信息不完整'
            });
        }
        // 获得文件的临时路径
        var tmp_path = req.files.file.path;
        console.log(tmp_path);
        // 指定文件上传后的目录 - 示例为"avatars"目录。
        var target_path = '../avatars/' + req.files.file.name;
        // 移动文件
        fs.rename(tmp_path, target_path, function(err) {
            if (err) {
                return res.json({
                    code: 0,
                    msg: err.toString()
                });
            }
            // 删除临时文件夹文件,
            fs.unlink(tmp_path, function(err) {
                if (err) throw err;
            });

        });
    });

ios客户端上传代码如下

NSString *username = [ZKConstValue getLoginStatus];
    if (!username && [username isEqualToString:@""]) {
        NSLog(@"ERROR: postImage,username is valide");
        return;
    }
    NSString  *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents/avatar_%@.png", username]];
    NSData *imageData = UIImagePNGRepresentation(image);
    [imageData writeToFile:pngPath atomically:YES];
    
    MKNetworkEngine *networkEngine = [[MKNetworkEngine alloc] initWithHostName:SERVER_URL_WITHOUT_HTTP];
    MKNetworkOperation *networkOperation = [networkEngine operationWithPath:[NSString stringWithFormat:@"avatar?username=%@", username] params:nil httpMethod:@"POST"];
    [networkOperation addFile:pngPath forKey:@"file" mimeType:@"image/png"];
    [networkOperation setFreezable:YES];
    
    [networkOperation addCompletionHandler:^(MKNetworkOperation *completedOperation) {
        NSString *responseString = [completedOperation responseString];
        NSLog(@"server response: %@",responseString);
    } errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
        NSLog(@"Upload avatar error: %@", error);
    }];
    [networkEngine enqueueOperation:networkOperation];
Request

curl -X POST “http://192.168.0.100:1337/avatar?username=dbngb” -F “file=@/var/mobile/Containers/Data/Application/1B756503-C0BC-4A36-8C76-480EE8111C1D/Documents/avatar_dbngb.png;type=image/png”

这样上传后在服务端打印req.files是undefine,也就是获取不到上传的文件。求帮帮忙!!!


7 回复

针对你遇到的问题,主要是在处理文件上传时,req.files 未被正确解析。这通常是因为缺少必要的中间件来处理 multipart/form-data 类型的请求。在 Node.js 中,常用的中间件有 multer

解决方案

首先安装 multer

npm install multer --save

接下来,我们需要对服务器端的代码进行修改以使用 multer 来处理文件上传。

修改后的服务器端代码

const express = require('express');
const multer = require('multer');
const path = require('path');

const app = express();

// 设置 Multer 存储配置
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname, 'avatars')); // 文件存储目录
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname)); // 文件名
  }
});

const upload = multer({ storage: storage });

app.post('/avatar', upload.single('file'), function(req, res) {
    if (!(req.query.username)) {
        return res.json({
            code: 0,
            msg: '参数信息不完整'
        });
    }

    const target_path = path.join(__dirname, 'avatars', req.file.filename);

    // 返回成功响应
    res.json({
        code: 1,
        msg: '文件上传成功',
        filePath: target_path
    });
});

iOS 客户端代码

你的 iOS 客户端代码看起来已经基本正确,但确保你使用的网络库(如 MKNetworkEngine)能够正确处理文件上传。

NSString *username = [ZKConstValue getLoginStatus];
if (!username || [username isEqualToString:@""]) {
    NSLog(@"ERROR: postImage, username is invalid");
    return;
}

UIImage *image = ...; // 获取你的图像
NSString *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents/avatar_%@.png", username]];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:pngPath atomically:YES];

MKNetworkEngine *networkEngine = [[MKNetworkEngine alloc] initWithHostName:SERVER_URL_WITHOUT_HTTP];
MKNetworkOperation *networkOperation = [networkEngine operationWithPath:[NSString stringWithFormat:@"avatar?username=%@", username] params:nil httpMethod:@"POST"];
[networkOperation addFile:pngPath forKey:@"file" mimeType:@"image/png"];
[networkOperation setFreezable:YES];

[networkOperation addCompletionHandler:^(MKNetworkOperation *completedOperation) {
    NSString *responseString = [completedOperation responseString];
    NSLog(@"Server response: %@", responseString);
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
    NSLog(@"Upload avatar error: %@", error);
}];
[networkEngine enqueueOperation:networkOperation];

总结

通过引入 multer,我们可以更好地处理文件上传。同时,确保客户端发送的请求格式符合服务器期望的格式。以上代码应能解决你遇到的问题,并且提供了更清晰的文件上传流程。


你有加bodyparser或者formidable之类的中间件吗 ps lz好厉害啊,移动开发前后端通吃啊

req.files是undefined肯定是因为你没有安装中间件。没捕获post请求

我已经加了bodyparser中间件,捕获post请求是什么意思

app.use(express.multipart({keepExtensions: true, uploadDir: ‘your_upload_path’})); 这是我express 3 的一个node.js的一段上传用得代码,楼主在app.js中是怎么配置的?

3楼正解,express 4.x以后我都是用的 connect-multiparty 中间件了来获取 req.files 了。

你的问题主要在于请求中 req.files 无法正确解析。通常这可能是因为缺少必要的中间件来处理文件上传,比如 multer

首先,你需要安装 multer 中间件:

npm install multer

然后,你可以使用 multer 来处理文件上传。以下是修改后的代码示例:

Node.js 服务端代码

const express = require('express');
const multer = require('multer');
const fs = require('fs');
const path = require('path');

const app = express();

// 配置 multer 存储策略
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './avatars'); // 存储文件的目录
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + '-' + file.originalname); // 使用时间戳加上原始文件名作为新文件名
  }
});

const upload = multer({ storage: storage });

app.post('/avatar', upload.single('file'), function (req, res) {
  if (!req.query.username) {
    return res.json({
      code: 0,
      msg: '参数信息不完整'
    });
  }

  const target_path = path.join(__dirname, 'avatars', req.file.filename);

  // 检查目标路径是否存在,如果不存在则创建目录
  if (!fs.existsSync(path.dirname(target_path))) {
    fs.mkdirSync(path.dirname(target_path), { recursive: true });
  }

  fs.rename(req.file.path, target_path, function (err) {
    if (err) {
      return res.json({
        code: 0,
        msg: err.toString()
      });
    }
    fs.unlink(req.file.path, function (err) {
      if (err) throw err;
    });

    res.json({
      code: 1,
      msg: '文件上传成功'
    });
  });
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

iOS 客户端代码

func uploadAvatar(image: UIImage, username: String) {
    let pngPath = NSTemporaryDirectory().appending("avatar_\(username).png")
    let imageData = image.pngData()
    imageData?.write(toFile: pngPath, atomically: true)

    let networkEngine = MKNetworkEngine(hostName: SERVER_URL)
    let networkOperation = networkEngine.operationWithPath("/avatar", params: ["username": username], httpMethod: "POST")
    networkOperation.addFile(pngPath, forKey: "file", mimeType: "image/png")

    networkOperation.completionBlock = {
        let responseString = networkOperation.responseText
        print("server response: \(responseString)")
    }

    networkOperation.errorBlock = { error in
        print("Upload avatar error: \(error)")
    }

    networkEngine.queue(networkOperation)
}

通过以上代码,你可以在 Node.js 服务端正确地处理文件上传,并将文件保存到指定的目录中。同时,iOS 客户端也可以正确地发送文件数据到服务器。

回到顶部