最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Multer Unique Filename - Stack Overflow

programmeradmin4浏览0评论

I had a doubt about Multer Filename.

When a multer stores the file with a random fileName then, can there be a case where two files have the same name in multer?

Basically what I want to say is If I am storing file from large numbers of users, can the filename get repeated? Can I trust multer on this or do I have to write a separate function to give a unique filename to each file?

I had a doubt about Multer Filename.

When a multer stores the file with a random fileName then, can there be a case where two files have the same name in multer?

Basically what I want to say is If I am storing file from large numbers of users, can the filename get repeated? Can I trust multer on this or do I have to write a separate function to give a unique filename to each file?

Share Improve this question edited May 11, 2021 at 14:27 Đăng Khoa Đinh 5,4113 gold badges17 silver badges36 bronze badges asked May 10, 2021 at 13:21 Tejas ShirnalkarTejas Shirnalkar 1531 silver badge8 bronze badges 3
  • Yes, you can trust it – user15388024 Commented May 10, 2021 at 13:22
  • thanks ! does it use date.now() only cause that can be reapeted? – Tejas Shirnalkar Commented May 10, 2021 at 13:27
  • It's open source. Here is the code you're interested in. – user15388024 Commented May 10, 2021 at 13:30
Add a ment  | 

3 Answers 3

Reset to default 9

From the npm page here, we can see Multer's example code to store a file on disk :

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, '/tmp/my-uploads')
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now())
  }
})
 
var upload = multer({ storage: storage })

The filename is concatenated with '-' + Date.now(). Date.now() give you the number of milliseconds from 1st January 1970. So, if 2 files are saved at different times, they have different names. And theoretically, if 2 files are saved on the system at exactly the same time (milliseconds unit) they will have the same name.

So, it does not depend on how many files you store but how fast requests e to your system. If you have more than 1000 requests per second, there will be a chance for duplication. In this case, you should use something like UUID. Otherwise, Date.now() does the work.

  • You can read more about Date.now()here.
  • Wikipedia page about UUID here, in case you need it. It also has a npm package.
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, '../media/');
    }
    ,
    filename: function (req, file, cb) {
        cb(null, file.fieldname + '-' + Date.now()+'.'+file.mimetype.split('/')[1]);
    }
});


const fileFilter = (req, file, cb) => {
    // reject a file
    if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
        cb(null, true);
    } else {
        cb(null, false);
    }
}

const upload = multer({
    storage: storage,
    limits: {
        fileSize: 1024 * 1024 * 5
    },
    fileFilter: fileFilter
}).single('profile_picture');

The uniqueness of each uploaded file is achieved by generating a filename that incorporates the current timestamp (in milliseconds) using Date.now() and appending it to the original fieldname of the uploaded file. This bination ensures that each file uploaded, even if they have the same original name, will have a different filename because the timestamp will be different at the time of upload. const multer = require('multer');

Timestamps should not, in general, be used to generate unique identifiers.

While for a single threaded application, where a low number of requests are made to an endpoint per second, the probability of a name collision is essentially zero, it is 2023 and we have been living in a world of big data, big tech platforms, and horizontal scalability for at least a decade now, so we should do things in a robust way.

Here's how to do it using the uuidv4 module:

const storage = multer.diskStorage({
  destination: (request, file, cb) => {
    cb(null, "./uploads/");
  },
  filename: (request, file, cb) => {
    // get a uuid
    const fileuuid = uuid();
    // get the filename extension from the original file name
    const uuidFilenameExtension = file.originalname.split(".").pop();
    // construct a new filename based on the uuid and preserve the
    // original extension
    const uuidFilename = fileuuid + "." + uuidFilenameExtension;
    cb(null, uuidFilename);
  },
});

Why is this important?

Consider horizontal scalability. Our application may one day be used to serve multiple millions of clients with many thousands of requests per second. With a resolution of milliseconds from the Date.now() function call, it is easy to see how if we were to use this to generate filenames we will encounter name conflicts. (Probably surprisingly often depending on user activity at peak times.)

We might scale our frontend but keep all uploaded images on the same storage server or filesystem - so duplications in names are not an unrealistic concern.

In regards to security: Do you really want a situation where two users upload a profile picture and one user is surprised to find their picture is of someone else? (You might consider how to write your application logic to ensure this cannot happen.)

When using UUIDs, it is not totally impossible to get name collisions, but the uncorrelated nature of sequential calls to a uuid creation function ensures the probability of this is low. If UUIDs are 128 bits in entropy, (they very often are) then this is double what most timestamps are. Timestamps are usually 64 bits long.

When calling a timestamp function, the results will be highly correlated because they are sequential in time. With cryptographic UUIDs this is not the case.

See also: https://www.npmjs./package/uuidv4

Addition - Deprecation Warning use v4:

DeprecationWarning: uuidv4() is deprecated. Use v4() from the uuid module instead.

If you get a warning about deprication use this module instead:

const { v4 } = require('uuid')

then

const fileuuid = v4();
发布评论

评论列表(0)

  1. 暂无评论