Sprawdź, czy obraz istnieje na serwerze przy użyciu JavaScript?

124

Czy za pomocą javascript można sprawdzić, czy zasób jest dostępny na serwerze? Na przykład mam obrazy 1.jpg - 5.jpg załadowane na stronę html. Chciałbym wywoływać funkcję JavaScript mniej więcej co minutę, która z grubsza wykonałaby następujący kod zdrapki ...

if "../imgs/6.jpg" exists:
    var nImg = document.createElement("img6");
    nImg.src = "../imgs/6.jpg";

Myśli? Dzięki!

0xhughes
źródło

Odpowiedzi:

209

Możesz użyć czegoś takiego:

function imageExists(image_url){

    var http = new XMLHttpRequest();

    http.open('HEAD', image_url, false);
    http.send();

    return http.status != 404;

}

Oczywiście możesz użyć jQuery / podobny do wykonania żądania HTTP.

$.get(image_url)
    .done(function() { 
        // Do something now you know the image exists.

    }).fail(function() { 
        // Image doesn't exist - do something else.

    })
ajtrichards
źródło
4
Ale nazwa funkcji nie powinna brzmieć fileExists, ponieważ działa to na .js .css .html lub innym publicznie dostępnym pliku.
KR
1
Funkcja jest niesamowita. Umieściłem to w swojej kolekcji :) Pomyślałem, fileExistsże będzie lepsza nazwa, ponieważ ta funkcja nie sprawdza, czy obraz istnieje na serwerze. Sprawdza, czy plik jest dostępny z serwera. Nie ma możliwości sprawdzenia, czy ten plik faktycznie jest obrazem. Może to być .pdf, .html, jakiś losowy plik o zmienionej nazwie na * .jpg lub * .png. Jeśli coś kończy się na .jpg, nie oznacza to, że jest to obraz w 100% :)
KR
9
To się nie powiedzie, chyba że dostęp do zasobu jest dozwolony zgodnie z regułami CORS. Korzystanie z Imageobiektu nie podlega temu ograniczeniu. Jedyną zaletą jest to, że faktycznie nie pobierze obrazu.
Alnitak
8
problem między domenami.
Amit Kumar,
2
To działa, ale pamiętaj, że przetwarzanie żądania zajmuje więcej czasu i nie jest najlepszym rozwiązaniem. Ponadto nie działa na cross origin (zdecydowanie w chrome), więc nie możesz go używać na protokole file: ///, co oznacza brak lokalnego użycia.
Cameron
119

Możesz użyć podstawowego sposobu działania modułu wstępnego ładowania obrazu, aby sprawdzić, czy obraz istnieje.

function checkImage(imageSrc, good, bad) {
    var img = new Image();
    img.onload = good; 
    img.onerror = bad;
    img.src = imageSrc;
}

checkImage("foo.gif", function(){ alert("good"); }, function(){ alert("bad"); } );

JSFiddle

epascarello
źródło
Hej, fajna funkcja! Na marginesie, jest to interesujący sposób zwracania wyników bezpośrednio do funkcji anonimowej. Normalnie zrobiłbym to za pomocą returnstwierdzenia takiego jak @ajtrichards w pierwszej części jego odpowiedzi.
Sablefoste
Absolutnie; ale nigdy tak naprawdę nie myślałem o innym sposobie bycia synchronicznym. Pochodzę z długiej historii kodowania proceduralnego i czasami brakuje mi „innego” sposobu patrzenia na rzeczy… Założę się, że nie jestem jedyny. ;-)
Sablefoste
2
Jeśli przyszli pracownicy Google będą mieli problem z tym rozwiązaniem, spróbuj przenieść definicję img.src na bezpośrednio po nowej linii Image.
Gavin
52

Możesz po prostu sprawdzić, czy obraz się ładuje, czy nie, używając wbudowanych zdarzeń, które są dostarczane dla wszystkich obrazów.

onloadI onerrorwydarzenia powie, czy obraz załadowany pomyślnie lub jeśli wystąpił błąd:

var image = new Image();

image.onload = function() {
    // image exists and is loaded
    document.body.appendChild(image);
}
image.onerror = function() {
    // image did not load

    var err = new Image();
    err.src = '/error.png';

    document.body.appendChild(err);
}

image.src = "../imgs/6.jpg";
adeneo
źródło
2
Najlepsza odpowiedź dla mnie, ponieważ działa w każdym przypadku (problem z połączeniem, zewnętrzny serwer ...) +1
Reign.85
2
Porównanie wydajności tej odpowiedzi z alternatywą AJAX.get. Ta odpowiedź działa znacznie szybciej!
Samuel
Podoba mi się to rozwiązanie, w każdym razie wprowadza zdarzenia w obu przypadkach (wykonanie asynchroniczne), które w niektórych sytuacjach mogą powodować problemy: w każdym przypadku sugerowałbym dołączenie obrazu, a następnie zastąpienie go tylko w przypadku błędów.
Giorgio Tempesta
@adeno, Czy to działa, gdy kod statusu: 404 Not Found
MahiMan
@Mahi - kod statusu nie powinien mieć znaczenia, o ile strona 404 w rzeczywistości nie zwróci prawidłowego obrazu, zakończy się niepowodzeniem i uruchomi errorprocedurę obsługi.
adeneo
15

Jeśli ktoś wejdzie na tę stronę i chce to zrobić w kliencie opartym na React , możesz zrobić coś takiego jak poniżej, która była oryginalną odpowiedzią dostarczoną przez Sophię Alpert z zespołu React tutaj

getInitialState: function(event) {
    return {image: "http://example.com/primary_image.jpg"};
},
handleError: function(event) {
    this.setState({image: "http://example.com/failover_image.jpg"});
},
render: function() {
    return (
        <img onError={this.handleError} src={src} />;
    );
}
Jordan Bonitatis
źródło
7

Lepszym i nowoczesnym podejściem jest użycie ES6 Fetch API do sprawdzenia, czy obraz istnieje, czy nie:

fetch('https://via.placeholder.com/150', { method: 'HEAD' })
    .then(res => {
        if (res.ok) {
            console.log('Image exists.');
        } else {
            console.log('Image does not exist.');
        }
    }).catch(err => console.log('Error:', err));

Upewnij się, że wykonujesz żądania tego samego pochodzenia lub na serwerze jest włączony mechanizm CORS.

attacomsian
źródło
6

Jeśli utworzysz tag obrazu i dodasz go do DOM, powinno zostać uruchomione zdarzenie onload lub onerror. Jeśli wystąpi błąd onerror, obraz nie istnieje na serwerze.

Douglas
źródło
3

Możesz wywołać tę funkcję JS, aby sprawdzić, czy plik istnieje na serwerze:

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;
    }
}
Ani Menon
źródło
1
Dobry wysiłek. ale trochę czasochłonne przy ładowaniu wielu obrazów w jednym formularzu.
Nuwan Withanage
pokazuje błąd w xhr.send (), jeśli adres URL nie istnieje.
Avinash Sharma,
3

Basicaly promisified wersja @espascarello i @adeneo odpowiedzi, z parametrem awaryjnej:

const getImageOrFallback = (path, fallback) => {
  return new Promise(resolve => {
    const img = new Image();
    img.src = path;
    img.onload = () => resolve(path);
    img.onerror = () => resolve(fallback);
  });
};

// Usage:

const link = getImageOrFallback(
  'https://www.fillmurray.com/640/360',
  'https://via.placeholder.com/150'
  ).then(result => console.log(result) || result)

// It can be also implemented using the async / await API.

Uwaga: rozwiązanie może mi się fetchbardziej podobać , ale ma wadę - jeśli Twój serwer jest skonfigurowany w określony sposób, może zwrócić 200/304, nawet jeśli Twój plik nie istnieje. To z drugiej strony wystarczy.

HynekS
źródło
2
Dla fetch, można użyć okwłasność responseobiektu, aby sprawdzić, czy wniosek był udany czy nie: fetch(url).then(res => {if(res.ok){ /*exist*/} else {/*not exist*/}});
attacomsian
To niestety nie działa, jeśli chcę sprawdzić prawidłowy obraz tła. background-image: url('/a/broken/url')daje mi 200i ok(Chrome 74).
HynekS
2

Możesz to zrobić za pomocą swoich axiosów, ustawiając względną ścieżkę do odpowiedniego folderu obrazów. Zrobiłem to, aby uzyskać plik JSON. Możesz wypróbować tę samą metodę dla pliku obrazu, możesz odnieść się do tych przykładów

Jeśli ustawiłeś już instancję axios z baseurl jako serwer w innej domenie, będziesz musiał użyć pełnej ścieżki do statycznego serwera plików, na którym wdrażasz aplikację internetową.

  axios.get('http://localhost:3000/assets/samplepic.png').then((response) => {
            console.log(response)
        }).catch((error) => {
            console.log(error)
        })

Jeśli obraz zostanie znaleziony, odpowiedź będzie wynosić 200, a jeśli nie, będzie to 404.

Ponadto, jeśli plik obrazu znajduje się w folderze zasobów wewnątrz src, możesz wykonać wymaganie, pobrać ścieżkę i wykonać powyższe wywołanie z tą ścieżką.

var SampleImagePath = require('./assets/samplepic.png');
axios.get(SampleImagePath).then(...)
Rohith Murali
źródło
0

To działa dobrze:

function checkImage(imageSrc) {
    var img = new Image();        
    try {
        img.src = imageSrc;
        return true;
    } catch(err) {
        return false;
    }    
}
MAtkins
źródło
12
Jesteś pewien, że to prawda za każdym razem?
Brandon McAlees
-3

Możesz odesłać ten link, aby sprawdzić, czy istnieje plik obrazu z JavaScript.

checkImageExist.js:

    var image = new Image();
    var url_image = './ImageFolder/' + variable + '.jpg';
    image.src = url_image;
    if (image.width == 0) {
       return `<img src='./ImageFolder/defaultImage.jpg'>`;
    } else {
       return `<img src='./ImageFolder/`+variable+`.jpg'`;
    } } ```
Atik Vhora
źródło
1
Właśnie to przetestowałem. To nie działa . Zawsze zwraca domyślny obraz. (Prawdopodobnie dlatego, że przeglądarka nie ma czasu na wysłanie żądania HTTP i załadowanie obrazu przed próbą przetestowania jego szerokości).
Quentin