【发布时间】:2018-08-31 19:09:52
【问题描述】:
我正在为网络上的网站图标实现图像缓存。在某一时刻,我有网站图标的 URL,并将其发送到我的页面,一切都很好。
现在,我将图标写入磁盘,使用我使用 URL 组件构建的伪唯一文件名。
这也有效,但只有当我写信给/tmp/!?
这是我的代码:
router.get('/favicon', function(req, res) {
favicon(req.query.url, function(err, iconUrl) {
if (iconUrl) {
var u = Url.parse(iconUrl);
request.get({url: iconUrl}, function (err, response, body) {
if (!err && typeof body !== 'undefined') {
var h = u.host.replace(/\//g, ''),
p = u.path.replace(/\//g, ''),
fileName;
fileName = path.join('/tmp', h + '.' + p);
// fileName = path.join(__dirname, '..', 'cache', h + '.' + p);
fs.writeFile(fileName, body, function(err) {
if(err)
console.log(err);
else
console.log("SAVED! (%s)", fileName);
});
} else {
console.log('### ERROR iconUrl: (%s) err: (%s)', iconUrl, err);
}
});
res.send(iconUrl);
} else {
res.status(500).send('No icon found');
}
});
});
这是在客户端(网络浏览器)端调用的,如下所示:
$.get("/favicon", {
url: decodeURI(feedHost),
dataType: "json",
timeout: 2000
}, function(iconURL) {
console.info('OK (icon: %s)', iconURL);
}).done(function(iconURL) {
console.info('OK (icon: %s)', iconURL);
}).fail(function() {
console.error('ERROR');
});
我虽然这是一个“磁盘已满”的问题,但不是,这是这台机器上的分区表,/home 分区内的项目目录(我的图像缓存目录所在的位置),/tmp/ 是,好吧,在/:
# df -h
Filesystem Size Used Avail Use% Mounted on
udev 1.9G 0 1.9G 0% /dev
tmpfs 388M 6.3M 382M 2% /run
/dev/sda6 19G 14G 3.8G 79% /
tmpfs 1.9G 23M 1.9G 2% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/loop0 82M 82M 0 100% /snap/core/4206
/dev/loop1 128M 128M 0 100% /snap/shotcut/20
/dev/loop2 82M 82M 0 100% /snap/core/4110
/dev/loop3 82M 82M 0 100% /snap/core/4017
/dev/loop4 298M 298M 0 100% /snap/shotcut/17
/dev/loop5 128M 128M 0 100% /snap/shotcut/21
/dev/sda5 121G 102G 14G 89% /home
tmpfs 388M 12K 388M 1% /run/user/1000
因此,当我使用上面的代码时,一切正常,/tmp/ 以异步方式填充图像,完美。
一旦我删除文件路径的前导/ - 当然指向有效路径 - 然后复制一个、两个、最多 3 个图标,然后该过程以某种方式失败,触发 .fail() 方法一个客户端,但服务器上没有任何错误。
帮助!
问题:
- 什么可能导致这个奇怪的“写入 2 或 3 个文件然后停止”问题?注意:服务器使用PM2 启动。
- 我的 ajax 调用 (JQuery
$.get()) 正确吗?为什么它会使页面中的其他 ajax 调用失败,而不是轻轻地出错然后继续?
更新
原来我没有在/tmp/ 中保存正确的图像文件;我现在正在使用此代码:
router.get('/favicon', function(req, res) {
favicon(req.query.url, function(err, iconUrl) {
if (iconUrl) {
if (!iconUrl.startsWith('..') && Url.parse(iconUrl)) {
var u = Url.parse(iconUrl),
h = u.host.replace(/\//g, ''),
p = u.path.replace(/\//g, ''),
fileName;
fileName = path.join('/tmp/cache', h + '.' + p);
// fileName = path.join(__dirname, '..', 'cache', h + '.' + p);
let stream = fs.createWriteStream(fileName);
stream.on('finish', function () {
console.log("SAVED %s (%s)", fileName, iconUrl);
}).on('error', function (err) {
console.log("NOT SAVED %s (%s)", fileName, err);
});
request(iconUrl).pipe(stream);
} else {
console.log('iconUrl NOT OK: (%s)', iconUrl);
}
res.send(iconUrl);
} else {
res.status(500).send('No icon found');
}
});
});
现在保存的文件是正确的图像文件;但是问题仍然存在,我现在已经在其他几台 (Linux) 机器 上测试了这段代码,包括生产网络服务器,同样的事情!无法在项目 repo 中保存(超过少数)文件,但如果我使用 /tmp/* 作为文件路径,一切都很好!
这让我发疯了,请让我摆脱这种痛苦:|
更新 2
我设法写入了我的主分区。我唯一不能写入的地方是项目目录内(包括)任何目录。
【问题讨论】:
-
看起来文件名包含一些特殊字符。您可以添加 console.log(fileName) 并查看它失败的文件吗?
-
嗨,亚历克斯;当我这样做时,我得到了我也可以在缓存中看到的 2 或 3 个文件的名称,它们都被命名为
subdomain.domain.tld.filename.extension。但同样,任何地方都不会触发错误:(请记住,当我使用/tmp/时,相同的文件被复制得很好。 -
嗯,好吧,我看不到你是否会转储错误...你可以在 function(err, response, body) { 之后添加 if (err) console.error(err) 吗?
-
我还进行了各种测试,其中
fileName只是Math.random()但结果相同:/tmp很好,本地 repo 路径失败:( -
是的,Alex,我 am 正在测试
body是否有错误。也不需要测试request.get(),因为它没有失败。我的意思是,如果我删除整个if (!err && typeof body !== 'undefined')一切运行正常。