在retina.js库中抑制404s

j7n*_*n7k 25 javascript http-status-code-404 retina.js

我们使用js lib retina.js,它将低质量图像与"视网膜"图像交换(大小乘以2).问题是,retina.js为每个无法找到的"视网膜"图像抛出404.

我们拥有一个网站,用户可以上传他们自己的图片,这些图片很可能不是视网膜分辨率.

有没有办法阻止js投掷404s?

如果你不知道lib.这是抛出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();
Run Code Online (Sandbox Code Playgroud)

tif*_*fon 28

我看到了一些选项来减轻这种情况.

增强并保持retina.js的HTTP调用结果缓存

对于设置为换出"1x"版本的任何给定"2x"图像,retina.js首先通过XMLHttpRequest请求验证图像的可用性.成功响应的路径缓存在数组中,并下载映像.

以下更改可能会提高效率:

  • XMLHttpRequest可以缓存失败的验证尝试:目前,只有先前成功的'2x'路径验证尝试才会被跳过.因此,失败的尝试可能会再次发生.在实践中,这与初始加载页面时验证过程发生的情况无关.但是,如果结果持续存在,跟踪故障将防止重复出现404错误.

  • 持续'2x'路径验证结果为localStorage:在初始化期间,retina.js可以检查localStorage结果缓存.如果找到一个,则可以绕过已经遇到的"2x"图像的验证过程,并且可以下载或跳过"2x"图像.可以验证新遇到的"2x"图像路径,并将结果添加到缓存中.从理论上讲,虽然localStorage可用,但每个浏览器的图像只会出现一次404.这将适用于域上任何页面的页面.

这是一个快速的检查.可能需要添加到期功能.

https://gist.github.com/4343101/revisions

使用HTTP重定向标头

我必须指出,我对"服务器端"问题的把握充其量只是参差不齐.请带上这个FWIW

另一个选项是服务器使用重定向代码来响应具有@2x字符且不存在的图像请求.看到这个相关的答案.

特别是:

如果您重定向图像并且它们是可缓存的,那么理想情况下,您可以在遥远的未来为日期设置HTTP Expires标头(以及相应的Cache-Control标头),因此至少在后续访问页面时用户不会再次进行重定向.

使用重定向响应将消除404并导致浏览器跳过后续尝试访问不存在的"2x"图像路径.

retina.js可以更具选择性

可以修改视网膜以排除一些图像.

与此相关的拉取请求:https://github.com/imulus/retinajs/commit/e7930be

根据pull请求,不是<img>按标签名称查找元素,而是可以使用CSS选择器,这可以是retina.js的可配置选项之一.可以创建一个CSS选择器,用于过滤掉用户上传的图像(以及预期不存在'2x'变体的其他图像).

另一种可能性是为可配置选项添加过滤功能.可以在每个匹配的<img>元素上调用该函数; a return true会导致下载'2x'变体,其他任何东西都会导致<img>跳过.

基本的默认配置会从当前版本更改为:

var config = {
  check_mime_type: true,
  retinaImgTagSelector: 'img',
  retinaImgFilterFunc: undefined
};
Run Code Online (Sandbox Code Playgroud)

Retina.init()函数将从当前版本更改为:

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();
  }
};
Run Code Online (Sandbox Code Playgroud)

window.onload火灾发生之前,请致电:

window.Retina.configure({

  // use a class 'no-retina' to prevent retinajs
  // from checking for a retina version
  retinaImgTagSelector : 'img:not(.no-retina)',

  // or, assuming there is a data-owner attribute
  // which indicates the user that uploaded the image:
  // retinaImgTagSelector : 'img:not([data-owner])',

  // or set a filter function that will exclude images that have
  // the current user's id in their path, (assuming there is a
  // variable userId in the global scope)
  retinaImgFilterFunc: function(img) {
    return img.src.indexOf(window.userId) < 0;
  }
});
Run Code Online (Sandbox Code Playgroud)

更新:清理并重组.添加了localStorage增强功能.


KTa*_*phy 8

简短回答:仅使用客户端JavaScript是不可能的

在浏览代码和一些研究之后,在我看来,retina.js并没有真正抛出404错误.

retina.js实际上正在做的是请求一个文件,只是根据错误代码检查它是否存在.这实际上意味着它要求浏览器检查文件是否存在.浏览器是给你404的东西,没有跨浏览器的方式来阻止它(我说"跨浏览器",因为我只检查了webkit).

但是,如果这确实是一个问题,你可以做的是在服务器端做一些事情来完全防止404s.

基本上这将是,例如,/retina.php?image = YOUR_URLENCODED_IMAGE_PATH一个请求,当视网膜图像存在时,可以返回此请求...

{"isRetina": true, "path": "YOUR_RETINA_IMAGE_PATH"}}
Run Code Online (Sandbox Code Playgroud)

如果它不...

{"isRetina": false, "path": "YOUR_REGULAR_IMAGE_PATH"}}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用一些JavaScript调用此脚本并根据需要解析响应.我并不是说这是唯一或最好的解决方案,只是一个可以工作的解决方案.


Joh*_*ger 7

Retina JS支持图像标签上的属性data-no-retina.这样它就不会试图找到视网膜图像.

寻找简单解决方案的其他人很有帮助.

<img src="/path/to/image" data-no-retina />
Run Code Online (Sandbox Code Playgroud)