Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni

🤖🚫 Контент вільний від AI. Цей пост на 100% написаний людиною, як і все на моєму блозі. Насолоджуйтесь!

10.10.2023

Чому деякі відповіді HTTP в Ruby отримують кодування ASCII-8BIT, а інші — ні

Почну з цього: в Ruby рядки мають кодування — на відміну від JS, Go, та різних інших мов. Тобто кожний конкретний рядок має конкретне кодування. Причому Ruby намагається приховати це, тому операції над рядками тихо перекодовують дані. Наприклад, якщо скласти два рядки, то результат отримує кодування першого рядка.

Як я писав в минулому, наразі ми майже завжди маємо справу з кодуванням UTF-8, тому важко помітити, що існують інші — принаймні, якщо ми не працюємо з двійковими даними. Так, зазвичай запит Net::HTTP.get() повертає рядок в UTF-8. Оскільки типова вебсторінка має саме це кодування (я навіть не зміг знайти протилежний приклад), то можна подумати, що звідти воно й береться. Але ні — насправді просто береться кодування за замовчуванням в Ruby.

Тому що Ruby взагалі не інтерпретує кодування, яке зазначене в відповіді HTTP. Цього не роблять тому, що інтерпретація не завжди однозначна. Ось обговорення. Є спеціальна опція response_body_encoding, яка або вказує кодування явно, або просить його все ж таки знайти з відповіді. (Або можна просто зробити .force_encoding результату, якщо вже знаєш, що туди передати.)

Звідки все ж таки тоді ASCII-8BIT? На це є точна відповідь. От звідси. А саме: якщо зміст відповіді передається стиснутим, тобто з Content-Encoding: gzip, то вмикається клас Inflater, який примусово перемикає результат в кодування ASCII-8BIT. Бо це є кодуванням для двійкових даних (те ж саме, що Encoding::BINARY.)

Мабуть, очікується, що саме двійкові дані будуть стиснуті? Але це навіть протилежно дійсності — бо найбільше користі від стискання текстів - HTML, CSS і так далі. Зображення, наприклад, самі по собі є стиснутими. А так виходить, що ми залежимо від налаштувань вебсервера, тобто .force_encoding все ж варто робити, принаймні для послідовності.