问题
So I'm trying to make a database, couple of function snippets that read, write or create X.json files. The way I imagined it to be is a DB folder, then within that folder bunch of username folders, and there, a bunch of files, like account.json, level.json, and so on... So each folder would keep users data, now, this is the code I managed to write so far, and it works. But the problem is, on the FS docs, it says that using fs.stat to check for the existence of the file before reading/writing to it is a bad idea. I don't understand why tho, as that seems like the only way to do it before I keep asking questions, I'd like to paste my code here:
socket.on('play', (data) => {
fs.stat(`db/${data.username}/account.json`, (error, result) => {
if(!error) {
fs.readFile(`db/${data.username}/account.json`, (error, result) => {
if(error) {
throw error;
} else {
const rawResult = JSON.parse(result);
if(data.password == rawResult.password) {
socket.emit('playResponse', {
success: true,
msg: 'Login Succesfull'
});
} else {
socket.emit('playResponse', {
success: false,
msg: 'Wrong Password!'
});
}
}
});
} else if(error.code == 'ENOENT') {
socket.emit('playResponse', {
success: false,
msg: 'Account not found'
});
}
});
});
I haven't written a general function that does this for me, because I figured that the code above is a mess right now. So, why is it a bad practice to check for the existence of the file (fs.stat) before writing/reading from them? I guess I could do something with the error I get from the readFile function and omit the fs.stat
function, but whenever readFile function comes across a folder that doesn't exist, my server just crashes.
I'm not very experienced with Node, so the code above is probably absolute nonsense. That's why I'm here!
How can I make my server not crash if the readFile comes across a non-existent folder, but instead just emit the "Account not Found" through socket.io? If I put that emit code there, my server just crashes anyway.
I would just go with MongoDB or something, but I have a loooot of free time and doing stuff like this is very fun for me. > Is using a DB like mongo like more secure, or do people do it so they don't have to waste time writing their own DB?
Thanks for your help!
回答1:
But the problem is, on the FS docs, it says that using fs.stat to check for the existence of the file before reading / writing to it is bad idea. I don't understand why tho
The reason is mentioned on the deprecated fs.exists
docs:
Using fs.exists() to check for the existence of a file before calling fs.open(), fs.readFile() or fs.writeFile() is not recommended. Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file does not exist.
How can I make my server not crash if the readFile comes across a non existent folder, but instead just emit the "Account not Found" through socket.io?
You don't handle the errors properly. As an example you throw an error in your .readFile
callback but your code leaves the error unhandled, that will "crash" your application. You could either wrap your code with a try/catch
block or use promises. Promises provide nice APIs to handle errors in your application. Node.js v10.0.0 introduces promise-wrapped APIs for fs
module APIs.
const fs = require('fs');
const fsPromises = fs.promises;
fsPromises.readFile(`db/${data.username}/account.json`).then(error => {
// the file exists and readFile could read it successfully!
// you can throw an error and the next `catch` handle catches the error
}).catch(error => {
// there was an error
});
You can also use the APIs with try/catch
and await
:
try {
const content = await fsPromises.readFile(`db/${data.username}/account.json`);
// the file exists and readFile could read it successfully!
} catch(error) {
// handle the possible error
}
If using node v10.0.0 is not an option you can use a npm package that provides promised-wrapped fs APIs like fs-extra or draxt:
// using draxt
const $ = require('draxt');
const File = $.File;
const file = new File(`db/${data.username}/account.json`);
file.read('utf8').then(contents => {
// the file exists and readFile could read it successfully!
}).catch(error => {
// handle the possible error
});
回答2:
The problem is that the file could be deleted betweent the time where you did got response the stat
call and the readFile
call.
The recommend way is to do call the readFile
and the check for the error code in the callback of the readFile
. For the callback based version this would look that way:
socket.on('play', (data) => {
fs.readFile(`db/${data.username}/account.json`, (error, result) => {
if (error) {
if (error.code === 'ENOENT') {
socket.emit('playResponse', {
success: false,
msg: 'Account not found'
})
} else {
// throw the error if you really want to exit the application for unknown errors
throw error
}
} else {
const rawResult = JSON.parse(result)
if (data.password === rawResult.password) {
socket.emit('playResponse', {
success: true,
msg: 'Login Succesfull'
})
} else {
socket.emit('playResponse', {
success: false,
msg: 'Wrong Password!'
})
}
}
})
})
来源:https://stackoverflow.com/questions/52236967/making-my-own-database-using-node-and-fs