JSONP: Секретное оружие фронтендера прошлого
Представьте, что вы — веб-разработчик в 2010 году. Вам нужно получить данные с чужого сервера, например, прогноз погоды или курс валют. Вы пишете простой fetch запрос, но в консоли браузера появляется красная ошибка: «No 'Access-Control-Allow-Origin' header is present». Знакомо?
Это Same-Origin Policy (политика одинакового источника) не пускает ваш JavaScript за пределы родного домена. Но как же тогда работали виджеты погоды, кнопки «Поделиться» и счётчики посещений? Ответ прост: они использовали JSONP — хитрый трюк, о котором мы сегодня и поговорим.
В этой статье мы ответим на популярный вопрос с Stack Overflow: «What is JSONP, and why was it created?» — простым языком, с примерами кода и без лишней теории.
1. Проблема: Почему браузер блокирует запросы?
Браузер — параноик. Он защищает пользователя от XSS-атак и кражи данных. Same-Origin Policy разрешает JavaScript читать ответы только с того же домена, протокола и порта.
Пример блокировки:
// Этот код вызовет ошибку CORS
fetch('https://api.distant-server.com/data')
.then(response => response.json())
.then(data => console.log(data));
Но есть одно исключение: <script> теги. Браузер спокойно загружает скрипты с любых доменов! Именно эту лазейку и использует JSONP.
2. Решение: JSONP — JSON с Padding'ом
JSONP (JSON with Padding) — это не технология и не формат данных, а паттерн (костыль), который обходит Same-Origin Policy через тег <script>.
Идея проста: вместо того чтобы делать запрос через XMLHttpRequest, мы динамически создаём <script> элемент, указываем URL сервера, и сервер возвращает не JSON, а JavaScript-код, который вызывает нашу функцию с данными.
Как выглядит обычный JSON:
// Ответ сервера (обычный JSON)
{"name": "PythonLib", "topic": "JSONP"}
Как выглядит JSONP:
// Ответ сервера (JSONP)
myCallback({"name": "PythonLib", "topic": "JSONP"});
Разница колоссальная: во втором случае сервер оборачивает данные в вызов функции myCallback. Это и есть тот самый padding (обёртка).
3. Практика: Пишем JSONP запрос своими руками
Давайте реализуем JSONP-клиент на чистом JavaScript. Это поможет понять магию.
function jsonp(url, callbackName) {
// 1. Создаём глобальную функцию (колбэк)
window[callbackName] = function(data) {
console.log('Данные получены:', data);
delete window[callbackName]; // Чистим за собой
document.body.removeChild(script);
};
// 2. Создаём тег script
const script = document.createElement('script');
script.src = `${url}?callback=${callbackName}`; // Передаём имя колбэка
script.onerror = function() {
console.error('Ошибка загрузки JSONP');
delete window[callbackName];
document.body.removeChild(script);
};
// 3. Добавляем в DOM — браузер сразу загружает и исполняет скрипт
document.body.appendChild(script);
}
// Используем:
jsonp('https://api.example.com/data', 'handleData');
Как это работает по шагам:
- Мы создаём глобальную функцию
handleData. - Добавляем тег
<script>с URL сервера. В URL мы передаём параметр?callback=handleData. - Сервер, поддерживающий JSONP, видит параметр
callbackи возвращает не JSON, а JavaScript:handleData({...}). - Браузер выполняет этот скрипт, вызывается наша функция, и мы получаем данные.
4. Почему JSONP — это зло? (Недостатки)
Если вы подумали: «Круто, буду везде использовать JSONP!» — не спешите. У этого метода есть фатальные недостатки:
- Только GET-запросы. Тег
<script>может делать только GET. Никаких POST, PUT или DELETE. - Нет обработки ошибок. Вы не узнаете HTTP-статус (404, 500). Скрипт либо загрузился, либо нет.
- Угроза безопасности. Вы доверяете чужому серверу выполнить любой JavaScript в вашем контексте. Если сервер взломают — прощай, данные пользователей.
- Глобальное загрязнение. Колбэки живут в глобальном объекте
window, что может вызвать конфликты.
5. Зачем JSONP создали, если он такой плохой?
Ответ — исторический контекст. JSONP появился в эпоху, когда CORS (Cross-Origin Resource Sharing) ещё не был стандартом. Первые черновики CORS появились в 2006 году, но браузеры начали массово поддерживать его только к 2012-2014 годам.
Разработчикам нужно было решение «здесь и сейчас». JSONP был единственным способом делать кросс-доменные запросы без серверного прокси. Его использовали:
- Google APIs (карты, поиск)
- Twitter (виджеты твитов)
- jQuery (метод
$.ajaxс типом данныхjsonp) - Счётчики аналитики (Google Analytics)
6. JSONP vs CORS: Кто победил?
Сегодня JSONP считается устаревшим. Единственный правильный способ делать кросс-доменные запросы — это CORS. Сервер просто добавляет заголовок:
Access-Control-Allow-Origin: *
И браузер перестаёт блокировать запросы. CORS поддерживает любые HTTP-методы, передаёт заголовки, позволяет обрабатывать ошибки и безопаснее.
Однако, если вы работаете с legacy-системой или API, которое до сих пор не поддерживает CORS, знание JSONP может спасти проект. Но для нового кода — забудьте про JSONP как про страшный сон.
7. Вопросы с собеседований (и Stack Overflow)
Чтобы закрепить материал, вот 3 вопроса, которые часто задают на собеседованиях:
Вопрос 1: Чем JSONP отличается от JSON?
Ответ: JSON — это формат данных. JSONP — это техника доставки этих данных, при которой они оборачиваются в вызов функции. JSONP не является форматом, это паттерн.
Вопрос 2: Можно ли использовать JSONP с fetch или XMLHttpRequest?
Блоги
Рекомендаций по книгам
Читайте также
Как устроиться TypeScript разработчиком: советы и резюме
Как обрезать std::string в C++: 5 рабочих способов для новичков и профи
ИИ-помощник в Swift: генерация кода без магии и страха
Массивы объектов в TypeScript: полный гайд с примерами
Уникальные элементы в массиве JavaScript: удаляем дубликаты изнутри