对于学校项目,我正在使用NodeJS和Express为KVM创建门户。
我需要调整XML文件,然后使用该XML文件创建VM。
所以我创建了2个函数
CreateXML:
function createXML(req, res, next) {
var parses = new xml2js.Parser();
fs.readFile('Debian7.xml', function(err, data){
parser.parseString(data, function (err, result){
result.domain.name = req.body.name;
result.domain.memory[0]['$'].unit = "GB";
result.domain.memory[0]['_'] = req.body.ram;
result.domain.currentMemory[0]['$'].unit = "GB";
result.domain.currentMemory[0]['_'] = req.body.ram;
result.domain.vcpu = req.body.cpus;
var builder = new xml2js.Builder({headless: true});
var xml = builder.buildObject(result);
fs.writeFile('./xmlfiles/' + req.body.name + '.xml', xml, function(err, data){
if(err) console.log(err);
});
});
});
};
则createdomain:
function createDomain(req, res){
var domainXML = fs.readFileSync('./xmlfiles/' + req.body.name + '.xml', 'utf8');
hypervisor.connect(function(){
hypervisor.createDomainAsync(domainXML).then(function (domain){
console.log('Domain Created');
res.json({success: true, msg: 'succesfully created domain'})
});
});
}
然后我在我的帖子请求中将这些函数称为中间件
apiRoutes.post('/domainCreate', createXML, createDomain);
但是当我在api路线上使用Postman时,我收到以下错误:
Error: ENOENT: no such file or directory, open './xmlfiles/rickyderouter23.xml'
错误之后它仍会创建XML文件,当我在使用postman之前创建XML文件时,它工作正常。它就像在创建XML文件之前需要执行这两个函数一样,如何在第一个函数之后创建XML文件,然后在第二个函数中使用它。
答案 0 :(得分:0)
答案是"它是异步的" (就像node.js / javascript中的很多很多问题一样。)
fs.readFile
函数是异步的:当你调用它时,你给它一个回调函数,当它完成加载文件时它会调用 。parser.parseString
是异步的 - 它会在完成解析XML时调用你的回调函数。fs.writeFile
是相同的 - 它会在完成文件写入后调用你的回调函数。hypervisor.connect
功能相同 - 它会在完成连接时调用您的回调函数。中间件函数按顺序调用,但它们都包含在返回之前可能尚未完成的代码。因此,当您的代码调用createDomain
并尝试读取createXML
中创建的XML文件时,XML文件可能尚未存在。 fs.readFile
可能尚未完成;即使它是,parser.parseString
函数可能还没有完成;即使一个已完成,fs.writeFile
可能尚未完成。
解决此问题的一种方法是将createXML
和createDomain
函数的功能集中到一个中间件函数中。这将允许您重写它,以便所有依赖于先前异步函数调用的函数调用实际上可以等待这些调用在执行之前完成。一个简单的方法就是:
function createXML(req, res, next) {
var parses = new xml2js.Parser();
fs.readFile('Debian7.xml', function(err, data){
parser.parseString(data, function (err, result){
result.domain.name = req.body.name;
result.domain.memory[0]['$'].unit = "GB";
result.domain.memory[0]['_'] = req.body.ram;
result.domain.currentMemory[0]['$'].unit = "GB";
result.domain.currentMemory[0]['_'] = req.body.ram;
result.domain.vcpu = req.body.cpus;
var builder = new xml2js.Builder({headless: true});
var xml = builder.buildObject(result);
fs.writeFile('./xmlfiles/' + req.body.name + '.xml', xml, function(err, data){
if(err) console.log(err);
// notice the call to createDomain here - this ensure
// that the connection to the hypervisor is not started
// until the file is written
createDomain(req, res);
});
});
});
};
并将您的路线更改为:
apiRoutes.post('/domainCreate', createXML);
现在,这非常难看。我不喜欢将这两个中间件功能集中在一起的想法,我宁愿重写它以使用基于承诺的方法,但这是基本的想法。