← Назад к вопросам

Как браузер понимает что перед ним картинка без расширения файла?

2.0 Middle🔥 131 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как браузер определяет тип файла без расширения

Браузер определяет тип файла несколькими способами, и расширение файла далеко не первичный - это важный момент для frontend-разработчика.

1. MIME Type в заголовке Content-Type

Это самый важный способ. Когда сервер отправляет файл, он включает заголовок Content-Type:

HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 12345

[бинарные данные изображения]

Браузер смотрит на значение Content-Type, а не на расширение файла в URL.

Проверка в консоли браузера:

fetch('/myfile')
  .then(res => {
    console.log(res.headers.get('Content-Type')) // image/png
    return res.blob()
  })
  .then(blob => {
    console.log(blob.type) // image/png
  })

2. Магические числа (Magic Bytes)

Внутри самого файла находятся сигнатуры - специальные последовательности байтов в начале файла, которые идентифицируют формат:

Примеры магических чисел:

PNG:  89 50 4E 47 (hex) = \x89PNG
JPEG: FF D8 FF (hex)
GIF:  47 49 46 38 (hex) = GIF8
PDF:  25 50 44 46 (hex) = %PDF
ZIP:  50 4B 03 04 (hex) = PK..
ELF:  7F 45 4C 46 (hex) = .ELF

Браузер может читать первые байты файла и определять тип по сигнатуре.

Как это работает в JavaScript:

async function getFileMimeType(blob) {
  const buffer = await blob.arrayBuffer()
  const bytes = new Uint8Array(buffer).slice(0, 4)
  
  // Проверка PNG
  if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4E && bytes[3] === 0x47) {
    return 'image/png'
  }
  
  // Проверка JPEG
  if (bytes[0] === 0xFF && bytes[1] === 0xD8) {
    return 'image/jpeg'
  }
  
  // Проверка GIF
  if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46) {
    return 'image/gif'
  }
  
  return 'unknown'
}

3. Расширение файла

Это наименее надежный способ, но браузер проверяет его как последний вариант:

<!-- Расширение в src -->
<img src="/images/photo" />  <!-- Браузер НЕ угадает формат только по расширению -->
<img src="/images/photo.jpg" />  <!-- Браузер знает это изображение -->

4. Контекст в HTML

Тег HTML также дает подсказку браузеру:

<!-- Для img тега браузер ожидает изображение -->
<img src="/file" />

<!-- Для video тега браузер ожидает видео -->
<video src="/file"></video>

<!-- Для audio тега браузер ожидает аудио -->
<audio src="/file"></audio>

Практический пример: неправильная конфигурация сервера

Проблема: Сервер отправляет картинку с неправильным MIME type:

// Неправильно на сервере (Express)
app.get('/image', (req, res) => {
  res.setHeader('Content-Type', 'text/plain') // НЕПРАВИЛЬНО!
  res.sendFile('./image.png')
})

// Браузер попытается отобразить как текст, не как изображение

Решение:

// Правильно
app.get('/image', (req, res) => {
  res.setHeader('Content-Type', 'image/png')
  res.sendFile('./image.png')
})

// Или лучше - пусть Express сам определит
app.use(express.static('public')) // Автоматически определит MIME type

Проверка типа файла при загрузке

const input = document.querySelector('input[type="file"]')

input.addEventListener('change', async (e) => {
  const file = e.target.files[0]
  
  // Способ 1: Проверка MIME type (может быть подделана)
  console.log(file.type) // image/jpeg
  
  // Способ 2: Проверка магических байтов (надежнее)
  const buffer = await file.slice(0, 4).arrayBuffer()
  const bytes = new Uint8Array(buffer)
  
  const isPNG = bytes[0] === 0x89 && bytes[1] === 0x50
  const isJPEG = bytes[0] === 0xFF && bytes[1] === 0xD8
  
  console.log({ isPNG, isJPEG })
})

Стандартные MIME типы для изображений

image/jpeg  - JPEG
image/png   - PNG
image/gif   - GIF
image/webp  - WebP
image/svg+xml - SVG
image/ico   - ICO (фавикон)
image/tiff  - TIFF

Почему это важно для frontend-разработчика

1. Загрузка файлов Нужно проверять реальный тип, не только расширение.

2. Проблемы с CDN и кэшем Если CDN неправильно кэшировал Content-Type, контент отобразится неправильно.

3. Безопасность Пользователь может загрузить .exe файл и переименовать в .jpg. Нужно проверять магические числа.

4. Работа с Blob'ами

const canvas = document.querySelector('canvas')
const blob = await new Promise(resolve => 
  canvas.toBlob(resolve, 'image/png')
)
console.log(blob.type) // 'image/png' - явно задали MIME type

Резюме приоритета определения типа

  1. Content-Type заголовок (70% ответственности)
  2. Магические числа файла (20% ответственности)
  3. Контекст HTML (5% ответственности)
  4. Расширение файла (5% ответственности - как последняя подсказка)

Влияние расширения файла намного меньше, чем думают новички. Браузер полагается прежде всего на MIME type в заголовках HTTP, что является частью правильной конфигурации веб-сервера.

Как браузер понимает что перед ним картинка без расширения файла? | PrepBro