如何在jQuery或纯JavaScript中检查文件是否存在?

298
如何在jQuery或纯JavaScript中检查服务器上的文件是否存在?
19个回答

461

使用jQuery:

$.ajax({
    url:'http://www.example.com/somefile.ext',
    type:'HEAD',
    error: function()
    {
        //file not exists
    },
    success: function()
    {
        //file exists
    }
});

编辑:

以下是检查404状态的代码,不使用jQuery

function UrlExists(url)
{
    var http = new XMLHttpRequest();
    http.open('HEAD', url, false);
    http.send();
    return http.status!=404;
}

稍作调整,它就可以检查HTTP状态码200(成功)。

编辑2:由于同步XMLHttpRequest已被弃用,因此您可以添加一个类似于这样的实用程序方法来进行异步操作:

function executeIfFileExist(src, callback) {
    var xhr = new XMLHttpRequest()
    xhr.onreadystatechange = function() {
        if (this.readyState === this.DONE) {
            callback()
        }
    }
    xhr.open('HEAD', src)
}

6
在你的纯JavaScript示例中,你应该在检查HTTP状态之前绑定OnReadyStateChange事件。 - RobertPitt
9
示例代码有问题,关于服务器发生了什么事情没有任何说明。原始问题相当模糊,但没有理由认为正在运行的服务器实际上将 URL 直接映射到文件系统。老实说,我不明白为什么这个答案如此受欢迎,因为它并没有真正解答问题所要求的内容。 - Pointy
80
可能是因为它解决了其他人在谷歌上搜索的问题。 - Ian Hunter
4
这会将文件加载到内存中吗?我想要检查文件是否存在,但不想加载文件。 - Brian
11
因其对最终用户体验的不利影响,主线程上的同步XMLHttpRequest已被弃用。有关更多帮助,请访问http://xhr.spec.whatwg.org/(此为浏览器发出的警告)。 - kupendra
显示剩余19条评论

80

一种类似且更为时新的方法。

$.get(url)
    .done(function() { 
        // exists code 
    }).fail(function() { 
        // not exists code
    })

3
为什么这个更加现代化?如果它更具向后兼容性,那么$.ajax似乎更好,对吗? - tim peterson
17
$.ajax同样可用,但success/error/complete函数已被弃用,建议使用promise、done/fail/always方法。了解更多信息,请访问http://api.jquery.com/jQuery.ajax/. 我在这里使用get,因为我们只关心一个简单的获取,但这只是$.ajax({url:url,type:'GET'})的简写。 - Matthew James Davis
5
如果图片不存在,控制台会输出404错误。有没有办法去除这个错误,因为我的应用程序始终期望其中一个图像不存在... - user1534664
2
不可能,参见:https://dev59.com/W2Qo5IYBdhLWcg3wDLpj#16379746。但这不会影响您的行为。它只会产生一些无关的日志记录。 - Matthew James Davis
1
我认为它们从未被弃用。很多人对于什么被弃用存在这种特定的误解。如果我错了,我很乐意接受纠正。jQuery不再是Web开发中首选的js库,但由于各种原因,仍有很多人在使用它。所以我想为他们澄清这一点。 - Vardhaman Deshpande
显示剩余11条评论

74

这对我有用:

function ImageExist(url) 
{
   var img = new Image();
   img.src = url;
   return img.height != 0;
}

2
虽然其他答案在其功能方面更好,但我+1此答案,因为这正是我要寻找的。只需记住,除非您首先加载内容,否则始终会获得零!即:window.addEventListener('load',function(){ - SpiRail
4
这是因为它设置了图像的源并立即检查图像的高度,但该图像尚未完成下载。你需要添加一个onload处理程序才能使其工作。出于这个原因,这不是一个可靠的方法。 - dudewad
如果像https://dev59.com/-Gct5IYBdhLWcg3wF5pF#12355031中那样添加img.onload处理程序,为什么不可靠? - Redoman
与ajax.get的替代方案相比,这个版本的性能要快得多! - Samuel
8
这个问题询问的是一个“文件”,而不是一张图片!如果这个 URL 存在但不是一个文件,它的高度将会是0!! - Apostolos
显示剩余2条评论

48

28
好的 — 不知道这一点。如果一张图片不存在,您可以执行以下操作来设置备用图片:<img src="image.gif" onerror="this.src='alternative.gif'"> - Ridcully
3
啊,但如果替代方案失败了呢?那么你就会陷入无尽的循环中,对吧? - rvighne
如果备选方案失败了,我想服务器端或程序员端可能存在更严重的问题。 :P - Erenor Paz
当设置alt图像以防止无限循环时,您可以始终将img标记的OnError设置为无。 - KingOfHypocrites
干得好,先生。运行得非常顺畅。 - hiren
2
未来的坏消息。这被标记为“已弃用。不适用于新网站。” https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img - keithpjolley

30

只要您在同一域上测试文件,这应该可以正常工作:

function fileExists(url) {
    if(url){
        var req = new XMLHttpRequest();
        req.open('GET', url, false);
        req.send();
        return req.status==200;
    } else {
        return false;
    }
}
请注意,此示例使用GET请求,除了获取头文件(您需要检查文件是否存在),还会获取整个文件。 如果文件足够大,此方法可能需要一些时间才能完成。
更好的方法是将这行更改为:req.open('GET', url, false); 改为req.open('HEAD', url, false);

7
抱歉,这与被接受的答案本质上是相同的。请忽略我。 - Moob
2
这是关于非jQuery表单的一些更多细节,可能会有所帮助。 - tim peterson
@Moob,这并不是“与被接受的答案基本相同”,你正在发送一个GET请求,这与HEAD请求有很大的区别。 - YemSalat
async: false,在Firefox 30.0及更高版本以及最近/当前版本的Chrome中同步操作已被弃用,因为用户体验不佳。尝试使用会导致失败/错误。应该使用带有回调函数的async: true进行异步操作。 - Kevin Fegan
请在继续执行JS之前等待响应。谢谢。 - vladanPro
我喜欢这种方法胜过官方答案。它测试文件是否实际可访问。我正在寻找一些能够考虑到文件可能存在,但权限被拒绝或其他许多可能的失败情况的东西。我将其用于将自定义样式表拉入应用程序的上下文中,仅当文件确实可以被拉入时。点赞。 :) - Bytech

21

如果您使用 Babel 转译器或 Typescript 2,这是使用 ES7 的方法:

async function isUrlFound(url) {
  try {
    const response = await fetch(url, {
      method: 'HEAD',
      cache: 'no-cache'
    });

    return response.status === 200;

  } catch(error) {
    // console.log(error);
    return false;
  }
}

然后在您的其他async作用域内,您可以轻松地检查url是否存在:

const isValidUrl = await isUrlFound('http://www.example.com/somefile.ext');

console.log(isValidUrl); // true || false

16

当我尝试运行这个问题的答案时,出现了跨域权限问题,因此我选择了:

function UrlExists(url) {
$('<img src="'+ url +'">').load(function() {
    return true;
}).bind('error', function() {
    return false;
});
}

看起来运行良好,希望能对某些人有所帮助!


3
我认为这会丢失布尔值,因为它们是从回调函数返回的,而不是从UrlExists函数返回的。 - mikebridge
这样行不通,你应该阅读这篇文章:https://dev59.com/RGYq5IYBdhLWcg3wwDRA - Hacketo
URL看起来是什么样子?带扩展名还是不带扩展名? - 151291

15

所有其他答案都可能因为缓存而失败!

向服务器发出HTTP请求以获取文件时,可以通过HTTP缓存截取并返回缓存的响应。但是,文件可能会在此期间从服务器中删除,因此忽略缓存可能会返回错误的结果。

正确的解决方案是创建不被缓存的HTTP HEAD请求,Nik Sumeiko的答案使用了no-cache头部,这意味着响应可以被缓存,但必须在重用之前重新验证。在这种情况下,服务器可能会返回304:未修改,这不是200:OK,因此会出现假阴性。

为了避免缓存,正确的标头是Cache-Control:no-store

文件可以存在而没有HTTP 200响应

你还应该记住,重定向301:永久重定向307:临时重定向308:永久重定向)可能会发生,因此文件可能存在于其他位置并可能从不同位置返回:根据用例,可以选择跟随重定向而不是在这种情况下返回false。

还要记住,如果你在不同的域中检查文件是否存在并且其CORS策略没有向你的服务器开放,则会阻止后台请求。在这种情况下,通常会返回403:禁止,这并不意味着文件不存在,而是文件不可用。最后但并非最不重要的,对于500:内部服务器错误响应也是适用的,这意味着HTTP服务器无法处理请求,但文件可能在其他地方可用,例如通过FTP。

以下代码将返回true,如果文件存在则为false,如果文件不可用或被重定向则为undefined:

const fileExists = file =>
  fetch(file, {method: 'HEAD', cache: 'no-store'})
  .then(response => ({200: true, 404: false})[response.status])
  .catch(exception => undefined);

fileExists("yourFile.html").then(yes => yes && alert("yourFile.html exists"));

// or in the async scope...
let yourFileExists = await fileExists("yourFile.html");
if(yourFileExists) console.log("It is there!")
else if(yourFileExists===false) console.log("Nope, it was deleted.");
else console.log("You are not worthy the answer, puny human!");

现代和过时的方法

既然我们现在生活在未来,我也建议:

  • $.ajax()已经过时,在新项目中不要使用
  • XMLHttpRequest()已经过时,在新项目中不要使用
  • fetch()是现代方法,如果可以选择,请使用它

注意 GET/POST方法(例如<img src...>)不适用于此处,因为它们通过下载文件浪费网络流量(想象一下最坏的情况:高分辨率照片和在网络连接质量差的地区使用付费移动数据的用户)

注意 现代PWA方法是使用Cache API和serviceWorker的fetch事件,该事件拦截客户端与HTTP缓存之间的通信。在链接示例中,应该有类似于以下内容:

if(event.request.cache=="no-store") {
    // avoid cache storage and pass the request in the chain
    // client - cache storage - HTTP cache - server
    return fetch(event.request);
}

如果没有这个设置,可能会忽略缓存设置,并且无法通过主线程检测正在运行的serviceWorker中的远程文件是否存在 - 在此处说明here


优秀的代码--请注意,如果您想在主要的安卓移动浏览器上使用此方法,只有2022年的浏览器更新才能处理它。您可能需要检查是否存在“fetch”(如果需要,检测以使用旧方法)以便包含它们。请参见https://caniuse.com/fetch。 - Jeff Clayton

5

我使用这个脚本来检查文件是否存在(同时它还处理了跨域问题):

$.ajax(url, {
       method: 'GET',
       dataType: 'jsonp'
         })
   .done(function(response) { 
        // exists code 
    }).fail(function(response) { 
        // doesnt exist
    })

请注意,当被检查的文件不包含JSON时,会抛出以下语法错误。

Uncaught SyntaxError: Unexpected token <


5

用于检查文件是否存在的JavaScript函数:

function doesFileExist(urlToFile)
{
    var xhr = new XMLHttpRequest();
    xhr.open('HEAD', urlToFile, false);
    xhr.send();

    if (xhr.status == "404") {
        console.log("File doesn't exist");
        return false;
    } else {
        console.log("File exists");
        return true;
    }
}

这是最简单的可行答案。而且它不需要异步。 - user2342558
我个人会将最后的if子句替换为return xhr.status == 200;,将其转换为返回布尔结果的函数,并将服务器错误视为指向无法访问的文件。 - Jonas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接