Cross-Domain Data Fetching Using JSONP in JavaScript
Standard XMLHttpRequest-based AJAX cannot retrieve resources from domains not explicitly permitted due to same-origin policy restrictions. JSONP bypasses this limitation by leveraging the ability of certain HTML tags, notably <script>, to load external resources.
A <script> tag fetches its source and executes it as JavaScript code. By requesting a server-side script that returns executable JavaScript, JSONP enables cross-domain data exchange without XHR.
Basic Server Response Example (PHP)
<?php
$username = $_REQUEST['usr'] ?? '';
echo "handleResponse('Greetings {$username}');";
?>
The PHP file above reads a usr parameter and responds with a call to a globally defined function handleResponse, emmbedding the data as a string argument.
Minimal Client Usage Without Encapsulation
<script>
function handleResponse(payload) {
console.log(payload);
}
</script>
<script src="http://localhost/api/greet.php?usr=admin"></script>
Loading the script triggers execution of handleResponse('Greetings admin').
Dynamic Script Injection Approach
To generalize usage, inject a <script> element at runtime:
<script>
document.addEventListener('click', () => {
const endpoint = 'http://localhost/api/greet.php';
performJsonp(endpoint, (result) => {
console.log(result);
}, { usr: 'root' });
});
function performJsonp(targetUrl, callbackFn, params) {
params = params || {};
let queryString = Object.keys(params).map(k => `${k}=${params[k]}`).join('&');
const scriptEl = document.createElement('script');
scriptEl.src = `${targetUrl}?${queryString}`;
document.body.appendChild(scriptEl);
window.receiveData = function(data) {
callbackFn(data);
};
}
</script>
Server-side must match the invoked global function name (receiveData).
Customizable Callback Parameter Name
Some APIs require specifying the callback name via a query key. Adjust the client to accommodate:
<script>
document.addEventListener('click', () => {
const endpoint = 'http://localhost/api/custom_cb.php';
performJsonp(endpoint, (msg) => {
alert(msg);
}, {
pwd: 'root',
cbField: 'callbackId',
callbackId: 'arbitraryName'
});
});
function performJsonp(targetUrl, onSuccess, args) {
args = args || {};
const qs = Object.keys(args)
.filter(key => key !== args.cbField)
.map(k => `${k}=${args[k]}`)
.join('&');
const scriptEl = document.createElement('script');
scriptEl.src = `${targetUrl}?${qs}&${args.cbField}=${args[args.cbField]}`;
document.body.appendChild(scriptEl);
window[args[args.cbField]] = function(response) {
onSuccess(response);
};
}
</script>
Server-side example matching custom callback key:
<?php
$password = $_REQUEST['pwd'] ?? '';
$cbName = $_REQUEST['callbackId'] ?? '';
echo "{$cbName}('Welcome {$password}');";
?>
Here, the server extracts both the data parameter (pwd) and the callback identifier (callbackId), then emits a call too the dynamically named function.