Javascript 在retina.js库中抑制404s
我们使用js库将低质量图像与“视网膜”图像交换(大小乘以2)。问题是,retina.js会对每个找不到的“retina”图像抛出404 我们有一个网站,用户可以上传他们自己的图片,这些图片很可能不是视网膜分辨率Javascript 在retina.js库中抑制404s,javascript,http-status-code-404,retina.js,Javascript,Http Status Code 404,Retina.js,我们使用js库将低质量图像与“视网膜”图像交换(大小乘以2)。问题是,retina.js会对每个找不到的“retina”图像抛出404 我们有一个网站,用户可以上传他们自己的图片,这些图片很可能不是视网膜分辨率 <img src="/path/to/image" data-no-retina /> 没有办法阻止js抛出404吗 如果你不知道图书馆。下面是抛出404的代码: http = new XMLHttpRequest; http.open('HEAD', this.at_2x
<img src="/path/to/image" data-no-retina />
没有办法阻止js抛出404吗
如果你不知道图书馆。下面是抛出404的代码:
http = new XMLHttpRequest;
http.open('HEAD', this.at_2x_path);
http.onreadystatechange = function() {
if (http.readyState != 4) {
return callback(false);
}
if (http.status >= 200 && http.status <= 399) {
if (config.check_mime_type) {
var type = http.getResponseHeader('Content-Type');
if (type == null || !type.match(/^image/i)) {
return callback(false);
}
}
RetinaImagePath.confirmed_paths.push(that.at_2x_path);
return callback(true);
} else {
return callback(false);
}
}
http.send();
http=newxmlhttprequest;
http.open('HEAD',this.at_2x_路径);
http.onreadystatechange=函数(){
如果(http.readyState!=4){
返回回调(false);
}
如果(http.status>=200&&http.status简短回答:仅使用客户端JavaScript是不可能的
在浏览了代码并进行了一些研究之后,我觉得retina.js并没有真正抛出404错误
retina.js实际做的是请求一个文件,并根据错误代码简单地检查它是否存在。这实际上意味着它是要求浏览器检查文件是否存在。浏览器是404的来源,没有跨浏览器的方法来阻止它(我说“跨浏览器”因为我只检查了webkit)
然而,如果这真的是一个问题,您可以做的是在服务器端做一些事情来完全防止404
本质上,这将是,例如,/retina.php?image=您的_URLENCODED_image_路径一个请求,当视网膜图像存在时,该请求可以返回此路径
{"isRetina": true, "path": "YOUR_RETINA_IMAGE_PATH"}}
如果不这样的话
{"isRetina": false, "path": "YOUR_REGULAR_IMAGE_PATH"}}
然后,您可以让一些JavaScript调用此脚本并根据需要解析响应。我不是说这是唯一或最好的解决方案,只是一个可行的解决方案。我看到了一些选项,可以缓解这一问题
增强并持久化retina.js的HTTP调用结果缓存
对于任何设置为交换“1x”版本的给定“2x”映像,retina.js首先通过XMLHttpRequest
请求验证映像的可用性。具有成功响应的路径缓存在数组中,并下载映像
以下更改可能会提高效率:
- 失败的
XMLHttpRequest
验证尝试可以被缓存:目前,只有在“2x”路径验证尝试以前成功的情况下才会跳过。因此,失败的尝试可能会再次出现。在实践中,这并不重要,因为验证过程是在最初加载页面时进行的。但是,如果结果是persisted,跟踪故障将防止再次出现404错误
- 在
localStorage
中保留“2x”路径验证结果:初始化期间,retina.js可以检查localStorage
中的结果缓存。如果找到结果缓存,则可以绕过已遇到的“2x”映像的验证过程,并且可以下载或跳过“2x”映像。新遇到的'可以验证2x'图像路径,并将结果添加到缓存中。理论上,虽然localStorage
可用,但对于每个浏览器的图像,404只会出现一次。这将适用于域中任何页面的跨页面
这是一个快速的工作。可能需要添加过期功能
使用HTTP重定向头
我必须注意的是,我对“服务器端”问题的理解充其量是零碎的。请接受这个FWIW
另一个选项是,对于包含@2x
字符且不存在的图像请求,服务器使用重定向代码进行响应。请参阅
特别是:
如果重定向图像且图像可缓存,则理想情况下应为遥远的将来的某个日期设置HTTP Expires标头(以及相应的缓存控制标头),以便至少在后续访问页面时,用户不必再次执行重定向
使用重定向响应将摆脱404,并导致浏览器跳过访问不存在的“2x”图像路径的后续尝试
retina.js可以更具选择性
可以修改retinajs以排除某些图像
与此相关的拉取请求:
根据pull请求,可以使用CSS选择器,而不是按标记名查找
元素,这可以是retina.js的可配置选项之一。可以创建一个CSS选择器,用于过滤用户上传的图像(以及预期不存在“2x”变体的其他图像)
另一种可能是在可配置选项中添加一个筛选函数。可以对每个匹配的
元素调用该函数;返回true
将导致下载“2x”变量,其他任何操作都将导致跳过
基本的默认配置将从更改为:
var config = {
check_mime_type: true,
retinaImgTagSelector: 'img',
retinaImgFilterFunc: undefined
};
Retina.init = function(context) {
if (context == null) context = root;
var existing_onload = context.onload || new Function;
context.onload = function() {
// uses new query selector
var images = document.querySelectorAll(config.retinaImgTagSelector),
retinaImages = [], i, image, filter;
// if there is a filter, check each image
if (typeof config.retinaImgFilterFunc === 'function') {
filter = config.retinaImgFilterFunc;
for (i = 0; i < images.length; i++) {
image = images[i];
if (filter(image)) {
retinaImages.push(new RetinaImage(image));
}
}
} else {
for (i = 0; i < images.length; i++) {
image = images[i];
retinaImages.push(new RetinaImage(image));
}
}
existing_onload();
}
};
Retina.init()
var config = {
check_mime_type: true,
retinaImgTagSelector: 'img',
retinaImgFilterFunc: undefined
};
Retina.init = function(context) {
if (context == null) context = root;
var existing_onload = context.onload || new Function;
context.onload = function() {
// uses new query selector
var images = document.querySelectorAll(config.retinaImgTagSelector),
retinaImages = [], i, image, filter;
// if there is a filter, check each image
if (typeof config.retinaImgFilterFunc === 'function') {
filter = config.retinaImgFilterFunc;
for (i = 0; i < images.length; i++) {
image = images[i];
if (filter(image)) {
retinaImages.push(new RetinaImage(image));
}
}
} else {
for (i = 0; i < images.length; i++) {
image = images[i];
retinaImages.push(new RetinaImage(image));
}
}
existing_onload();
}
};
更新:清理并重新组织。添加了localStorage
增强功能。retina.js对于静态网页上的固定图像是一个很好的工具,但是如果您要检索用户上传的图像,正确的工具是服务器端。我想象这里是PHP,但是相同的逻辑可以应用于任何服务器端语言
如果上传图像的一个好的安全习惯是不让用户通过直接url访问它们:如果用户成功地将恶意脚本上传到您的服务器,他应该不能通过url启动它(www.yoursite.com/upload/mymaliciousscript.php
)。因此,如果可以的话,通常通过一些脚本检索上传的图像是一个好习惯…(更好的是,将上传文件夹放在文档根目录之外)
现在,get_image.php脚本可以获得相应的图像123456.jpg或123456@2x.jpg取决于某些条件
这种方法似乎非常适合你的情况
<?php
$source_file = ...
$retina_file = ....
if (isset($_COOKIE['devicePixelRatio'])) {
$cookie_value = intval($_COOKIE['devicePixelRatio']);
}
if ($cookie_value !== false && $cookie_value > 1) {
// Check if retina image exists
if (file_exists($retina_file)) {
$source_file = $retina_file;
}
}
....
header('Content-Length: '.filesize($source_file), true);
readfile($source_file); // or read from db, or create right size.. etc..
?>
http = new XMLHttpRequest;
http.open('HEAD', "/image.php?p="+this.at_2x_path);
http.onreadystatechange = function() {
if (http.readyState != 4) {
return callback(false);
}
if (http.status >= 200 && http.status <= 399) {
if (config.check_mime_type) {
var type = http.getResponseHeader('Content-Type');
if (type == null || !type.match(/^image/i)) {
return callback(false);
}
}
RetinaImagePath.confirmed_paths.push(that.at_2x_path);
return callback(true);
} else {
return callback(false);
}
}
http.send();
<?php
if(file_exists($_GET['p'])){
$ext = explode('.', $_GET['p']);
$ext = end($ext);
if($ext=="jpg") $ext="jpeg";
header("Content-Type: image/".$ext);
echo file_get_contents($_GET['p']);
}
?>
retinaImages.push(new RetinaImage(image));
if(image.src.match(/@1x\.\w{3}$/)) {
image.src = image.src.replace(/@1x(\.\w{3})$/,"$1");
retinaImages.push(new RetinaImage(image));
}
<img src="/path/to/image" data-no-retina />