6

Verify if a url links to an image (without relying on regex)

 1 year ago
source link: https://www.zhenghao.io/posts/verify-image-url
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Verify if a url links to an image (without relying on regex)

#javascript
Published on 14 June, 2022

one of the rare cases that I need to work with MIME types in frontend web development

In a side project I built, I had an input field that let users to pass urls that are supposed to link to image files, and I wanted to add client-side validation for that.

I started with the most obvious solution: regular expressions.

Regex#

A list of common image file types that are supported by most browsers can be found on this MDN page. I can check if the url ends with one of these filename extensions:

function isImgUrl(url) {
  return /\.(jpg|jpeg|png|webp|avif|gif)$/.test(url)
}

However, not only do I have to list out every single possible image filename extension in the regex, this approach wrongly assumes that all urls must have the correct filename extension appended at the end, which isn't always the case. For example, the url of my github profile picture (https://avatars.githubusercontent.com/u/33640448?v=4) links to an image, but it doesn't end up with any image filename extension. The current solution doesn't cover this edge case.

Image's onload event#

Another approach is to create an image tag <img > dynamically in JavaScript and assigning the url to its src attribute. If the onload event fires off, then that means the browser can correctly decode the image data linked by the url. Thus we know it is indeed an image url.

function isImgUrl(url) {
  const img = new Image();
  img.src = url;
  return new Promise((resolve) => {
    img.onload = () => resolve(true);
    img.onerror = () => resolve(false);
  });
}

Now it works with urls that don't have the filename extensions attached.

function isImgUrl(url) {
  const img = new Image();
  img.src = url;
  return new Promise((resolve) => {
    img.onerror = () => resolve(false);
    img.onload = () => resolve(true);
  });
}

const urls = [
  'https://avatars.githubusercontent.com/u/33640448?v=4',
  'https://httpbin.org/image/webp',
  'https://upload.wikimedia.org/wikipedia/commons/a/a3/June_odd-eyed-cat.jpg'
];

Promise.all(urls.map((url) => isImgUrl(url))).then(console.log); // [true, true ,true]

However, by assigning the url to the src attribute of an image tag, the browser kicks off a Get request to download the whole image when we don't plan to actually render anything yet. This solution doesn't scale well if we have hundreds of urls to check.

Sending HEAD requests and only check for the MIME type#

Turns out there is a way to find out if a url links to an image file without incurring the cost of downloading. That is, to send a HEAD request to get the MIME type from the Content-Type header.

function isImgUrl(url) {
  return fetch(url, {method: 'HEAD'}).then(res => {
    return res.headers.get('Content-Type').startsWith('image')
  })
}

This works because all supported image types are nicely grouped under the image/ MIME type. For example, the MIME type of a jpeg file is image/jpeg , and for a png file it is image/png , so we just need to check if the MIME type starts with the word image.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK