JSONP: The Secret Weapon of Frontend Developers from the Past
\nImagine you're a web developer in 2010. You need to get data from someone else's server, for example, a weather forecast or currency exchange rates. You write a simple fetch request, but a red error appears in the browser console: «No 'Access-Control-Allow-Origin' header is present». Sound familiar?
This is the Same-Origin Policy preventing your JavaScript from accessing anything outside your own domain. But how did weather widgets, «Share» buttons, and visitor counters work back then? The answer is simple: they used JSONP — a clever trick that we'll discuss today.
\nIn this article, we'll answer the popular Stack Overflow question: «What is JSONP, and why was it created?» — in simple terms, with code examples and no unnecessary theory.
\n\n1. The Problem: Why Does the Browser Block Requests?
\nThe browser is paranoid. It protects the user from XSS attacks and data theft. The Same-Origin Policy only allows JavaScript to read responses from the same domain, protocol, and port.
\nExample of a blocked request:
\n// This code will cause a CORS error\nfetch('https://api.distant-server.com/data')\n .then(response => response.json())\n .then(data => console.log(data));\nBut there is one exception: <script> tags. The browser freely loads scripts from any domain! This is exactly the loophole that JSONP exploits.
\n\n2. The Solution: JSONP — JSON with Padding
\nJSONP (JSON with Padding) is not a technology or a data format, but a pattern (workaround) that bypasses the Same-Origin Policy using the <script> tag.
The idea is simple: instead of making a request via XMLHttpRequest, we dynamically create a <script> element, point it to the server's URL, and the server returns not JSON, but JavaScript code that calls our function with the data.
What regular JSON looks like:
\n// Server response (regular JSON)\n{"name": "PythonLib", "topic": "JSONP"}\n\nWhat JSONP looks like:
\n// Server response (JSONP)\nmyCallback({"name": "PythonLib", "topic": "JSONP"});\nThe difference is huge: in the second case, the server wraps the data in a call to the myCallback function. This is the so-called padding (wrapper).
3. Practice: Writing a JSONP Request by Hand
\nLet's implement a JSONP client in pure JavaScript. This will help you understand the magic.
\n\nfunction jsonp(url, callbackName) {\n // 1. Create a global function (callback)\n window[callbackName] = function(data) {\n console.log('Data received:', data);\n delete window[callbackName]; // Clean up after ourselves\n document.body.removeChild(script);\n };\n\n // 2. Create a script tag\n const script = document.createElement('script');\n script.src = `${url}?callback=${callbackName}`; // Pass the callback name\n script.onerror = function() {\n console.error('JSONP load error');\n delete window[callbackName];\n document.body.removeChild(script);\n };\n\n // 3. Add to the DOM — the browser immediately loads and executes the script\n document.body.appendChild(script);\n}\n\n// Usage:\njsonp('https://api.example.com/data', 'handleData');\nHow it works step by step:
\n- \n
- We create a global function
handleData. \n - We add a
<script>tag with the server's URL. In the URL, we pass the parameter?callback=handleData. \n - The server, supporting JSONP, sees the
callbackparameter and returns not JSON, but JavaScript:handleData({...}). \n - The browser executes this script, our function is called, and we receive the data. \n
4. Why is JSONP Evil? (Disadvantages)
\nIf you thought: «Cool, I'll use this everywhere