ฉันสามารถสร้างคำขอข้ามโดเมน JSONP ใน JavaScript โดยไม่ใช้ jQuery หรือไลบรารีภายนอกอื่น ๆ ได้หรือไม่ ฉันต้องการใช้ JavaScript เองแล้วแยกวิเคราะห์ข้อมูลและทำให้มันเป็นวัตถุเพื่อที่ฉันจะได้ใช้มัน ฉันต้องใช้ไลบรารีภายนอกหรือไม่? ถ้าไม่ฉันจะทำอย่างไร?
ฉันสามารถสร้างคำขอข้ามโดเมน JSONP ใน JavaScript โดยไม่ใช้ jQuery หรือไลบรารีภายนอกอื่น ๆ ได้หรือไม่ ฉันต้องการใช้ JavaScript เองแล้วแยกวิเคราะห์ข้อมูลและทำให้มันเป็นวัตถุเพื่อที่ฉันจะได้ใช้มัน ฉันต้องใช้ไลบรารีภายนอกหรือไม่? ถ้าไม่ฉันจะทำอย่างไร?
คำตอบ:
function foo(data)
{
// do stuff with JSON
}
var script = document.createElement('script');
script.src = '//example.com/path/to/jsonp?callback=foo'
document.getElementsByTagName('head')[0].appendChild(script);
// or document.head.appendChild(script) in modern browsers
foo(payload_of_json_data)
ความคิดที่ว่าเมื่อโหลดลงในแท็กสคริปต์จะเรียกฟังก์ชัน foo ที่มี payload อยู่แล้วว่าเป็นวัตถุจาวาสคริปต์และไม่จำเป็นต้องแยกวิเคราะห์
ตัวอย่างน้ำหนักเบา (พร้อมการรองรับ onSuccess และ onTimeout) คุณต้องส่งชื่อเรียกกลับภายใน URL หากคุณต้องการ
var $jsonp = (function(){
var that = {};
that.send = function(src, options) {
var callback_name = options.callbackName || 'callback',
on_success = options.onSuccess || function(){},
on_timeout = options.onTimeout || function(){},
timeout = options.timeout || 10; // sec
var timeout_trigger = window.setTimeout(function(){
window[callback_name] = function(){};
on_timeout();
}, timeout * 1000);
window[callback_name] = function(data){
window.clearTimeout(timeout_trigger);
on_success(data);
}
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = src;
document.getElementsByTagName('head')[0].appendChild(script);
}
return that;
})();
ตัวอย่างการใช้งาน:
$jsonp.send('some_url?callback=handleStuff', {
callbackName: 'handleStuff',
onSuccess: function(json){
console.log('success!', json);
},
onTimeout: function(){
console.log('timeout!');
},
timeout: 5
});
ที่ GitHub: https://github.com/sobstel/jsonp.js/blob/master/jsonp.js
JSONP คืออะไร
สิ่งสำคัญที่ต้องจำไว้สำหรับ jsonp คือมันไม่ใช่โปรโตคอลหรือชนิดข้อมูล เป็นเพียงวิธีการโหลดสคริปต์ในทันทีและประมวลผลสคริปต์ที่แนะนำในหน้าเว็บ ตามเจตนารมณ์ของ JSONP หมายถึงการนำอ็อบเจ็กต์ javascript ใหม่จากเซิร์ฟเวอร์เข้าสู่ไคลเอ็นต์แอ็พพลิเคชัน / สคริปต์
JSONP จำเป็นเมื่อใด
เป็นวิธีการ 1 ในการอนุญาตให้โดเมนหนึ่งเข้าถึง / ประมวลผลข้อมูลจากอีกโดเมนหนึ่งในเพจเดียวกันโดยไม่ตรงกัน โดยทั่วไปจะใช้เพื่อลบล้างข้อ จำกัด CORS (Cross Origin Resource Sharing) ซึ่งจะเกิดขึ้นกับคำขอ XHR (ajax) การโหลดสคริปต์ไม่อยู่ภายใต้ข้อ จำกัด ของ CORS
เป็นอย่างไรบ้าง
การแนะนำอ็อบเจ็กต์ javascript ใหม่จากเซิร์ฟเวอร์สามารถนำไปใช้งานได้หลายวิธี แต่วิธีปฏิบัติที่พบบ่อยที่สุดคือให้เซิร์ฟเวอร์ดำเนินการเรียกใช้ฟังก์ชัน 'เรียกกลับ' โดยส่งผ่านอ็อบเจ็กต์ที่ต้องการเข้าไป ฟังก์ชันเรียกกลับเป็นเพียงฟังก์ชันที่คุณได้ตั้งค่าไว้บนไคลเอนต์ซึ่งสคริปต์ที่คุณโหลดการโทร ณ จุดที่สคริปต์โหลดเพื่อประมวลผลข้อมูลที่ส่งผ่านไป
ตัวอย่าง:
ฉันมีแอปพลิเคชันที่บันทึกรายการทั้งหมดในบ้านของใครบางคน แอปพลิเคชันของฉันได้รับการตั้งค่าและตอนนี้ฉันต้องการเรียกคืนรายการทั้งหมดในห้องนอนหลัก
app.home.com
แอพลิเคชันของฉันอยู่บน APIs api.home.com
ที่ฉันจำเป็นต้องโหลดข้อมูลจากที่อยู่บน
เว้นแต่ว่าเซิร์ฟเวอร์จะได้รับการตั้งค่าอย่างชัดเจนเพื่ออนุญาตฉันไม่สามารถใช้ ajax เพื่อโหลดข้อมูลนี้ได้เนื่องจากแม้แต่เพจในโดเมนย่อยที่แยกจากกันก็อยู่ภายใต้ข้อ จำกัด XHR CORS
ตามหลักการแล้วตั้งค่าเพื่ออนุญาต x-domain XHR
ตามหลักการแล้วเนื่องจาก api และแอปอยู่ในโดเมนเดียวกันฉันจึงอาจมีสิทธิ์เข้าถึงเพื่อตั้งค่าส่วนหัวapi.home.com
ได้ ถ้าผมทำผมสามารถเพิ่มรายการส่วนหัวอนุญาตให้เข้าถึงAccess-Control-Allow-Origin:
app.home.com
สมมติว่ามีการตั้งค่าส่วนหัวดังนี้Access-Control-Allow-Origin: "http://app.home.com"
ซึ่งปลอดภัยกว่าการตั้งค่า JSONP มาก เนื่องจากapp.home.com
สามารถรับทุกสิ่งที่ต้องการได้api.home.com
โดยไม่ต้องapi.home.com
ให้ CORS เข้าถึงอินเทอร์เน็ตทั้งหมด
โซลูชัน XHR ข้างต้นไม่สามารถทำได้ ตั้งค่า JSONP บนสคริปต์ไคลเอ็นต์ของฉัน: ฉันตั้งค่าฟังก์ชันเพื่อประมวลผลการตอบกลับจากเซิร์ฟเวอร์เมื่อฉันทำการเรียก JSONP :
function processJSONPResponse(data) {
var dataFromServer = data;
}
เซิร์ฟเวอร์จะต้องได้รับการตั้งค่าเพื่อส่งคืนมินิสคริปต์ที่มีลักษณะบางอย่างเช่น"processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"
อาจได้รับการออกแบบให้ส่งคืนสตริงดังกล่าวหาก//api.home.com?getdata=room&room=main_bedroom
มีการเรียกสิ่งที่ต้องการ
จากนั้นไคลเอนต์ตั้งค่าแท็กสคริปต์ดังนี้:
var script = document.createElement('script');
script.src = '//api.home.com?getdata=room&room=main_bedroom';
document.querySelector('head').appendChild(script);
สิ่งนี้จะโหลดสคริปต์และเรียกทันทีwindow.processJSONPResponse()
ตามที่เขียน / สะท้อน / พิมพ์โดยเซิร์ฟเวอร์ ข้อมูลที่ส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันจะถูกเก็บไว้ในdataFromServer
ตัวแปรโลคัลและคุณสามารถทำอะไรก็ได้
ทำความสะอาด
เมื่อลูกค้ามีข้อมูลเช่น. ทันทีหลังจากเพิ่มสคริปต์ไปยัง DOM องค์ประกอบสคริปต์สามารถลบออกจาก DOM:
script.parentNode.removeChild(script);
SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
ผมได้รับ หลังจากเพิ่มคำพูดเดียวลงในข้อมูลทุกอย่างก็ทำงานได้ดีดังนั้น:"processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"
ความเข้าใจของฉันคือคุณใช้แท็กสคริปต์กับ JSONP จริงๆดังนั้น ...
ขั้นตอนแรกคือการสร้างฟังก์ชันของคุณที่จะจัดการ JSON:
function hooray(json) {
// dealin wit teh jsonz
}
ตรวจสอบให้แน่ใจว่าฟังก์ชันนี้สามารถเข้าถึงได้ในระดับโลก
จากนั้นเพิ่มองค์ประกอบสคริปต์ใน DOM:
var script = document.createElement('script');
script.src = 'http://domain.com/?function=hooray';
document.body.appendChild(script);
สคริปต์จะโหลด JavaScript ที่ผู้ให้บริการ API สร้างขึ้นและเรียกใช้งาน
eval
หรือparse
หรืออะไร คุณควรได้รับ JavaScript ที่เบราว์เซอร์สามารถเรียกใช้งานได้ใช่ไหม?
วิธีที่ฉันใช้ jsonp ดังนี้:
function jsonp(uri) {
return new Promise(function(resolve, reject) {
var id = '_' + Math.round(10000 * Math.random());
var callbackName = 'jsonp_callback_' + id;
window[callbackName] = function(data) {
delete window[callbackName];
var ele = document.getElementById(id);
ele.parentNode.removeChild(ele);
resolve(data);
}
var src = uri + '&callback=' + callbackName;
var script = document.createElement('script');
script.src = src;
script.id = id;
script.addEventListener('error', reject);
(document.getElementsByTagName('head')[0] || document.body || document.documentElement).appendChild(script)
});
}
จากนั้นใช้วิธี 'jsonp' ดังนี้:
jsonp('http://xxx/cors').then(function(data){
console.log(data);
});
อ้างอิง:
JavaScript XMLHttpRequest โดยใช้ JsonP
http://www.w3ctech.com/topic/721 (พูดคุยเกี่ยวกับวิธีการใช้ Promise)
ฉันมีไลบรารี javascript ที่บริสุทธิ์เพื่อทำเช่นนั้นhttps://github.com/robertodecurnex/J50Npi/blob/master/J50Npi.js
ลองดูและแจ้งให้เราทราบหากคุณต้องการความช่วยเหลือในการใช้หรือทำความเข้าใจโค้ด
Btw คุณมีตัวอย่างการใช้งานง่ายๆที่นี่: http://robertodecurnex.github.com/J50Npi/
/**
* Loads data asynchronously via JSONP.
*/
const load = (() => {
let index = 0;
const timeout = 5000;
return url => new Promise((resolve, reject) => {
const callback = '__callback' + index++;
const timeoutID = window.setTimeout(() => {
reject(new Error('Request timeout.'));
}, timeout);
window[callback] = response => {
window.clearTimeout(timeoutID);
resolve(response.data);
};
const script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = url + (url.indexOf('?') === -1 ? '?' : '&') + 'callback=' + callback;
document.getElementsByTagName('head')[0].appendChild(script);
});
})();
const data = await load('http://api.github.com/orgs/kriasoft');
window[callback] = null
อนุญาตให้ฟังก์ชันเป็นที่เก็บขยะ
ฉันเขียนห้องสมุดเพื่อจัดการเรื่องนี้อย่างง่ายที่สุด ไม่จำเป็นต้องทำให้ภายนอกเป็นเพียงฟังก์ชันเดียว ซึ่งแตกต่างจากตัวเลือกอื่น ๆ สคริปต์นี้จะล้างข้อมูลในภายหลังและเป็นข้อมูลทั่วไปสำหรับการร้องขอเพิ่มเติมในรันไทม์
https://github.com/Fresheyeball/micro-jsonp
function jsonp(url, key, callback) {
var appendParam = function(url, key, param){
return url
+ (url.indexOf("?") > 0 ? "&" : "?")
+ key + "=" + param;
},
createScript = function(url, callback){
var doc = document,
head = doc.head,
script = doc.createElement("script");
script
.setAttribute("src", url);
head
.appendChild(script);
callback(function(){
setTimeout(function(){
head
.removeChild(script);
}, 0);
});
},
q =
"q" + Math.round(Math.random() * Date.now());
createScript(
appendParam(url, key, q), function(remove){
window[q] =
function(json){
window[q] = undefined;
remove();
callback(json);
};
});
}
โปรดดูJavaScript
ตัวอย่างด้านล่างเพื่อJSONP
โทรออกโดยไม่ใช้ JQuery:
นอกจากนี้คุณสามารถอ้างอิงที่GitHub
เก็บของฉันเพื่ออ้างอิง
https://github.com/shedagemayur/JavaScriptCode/tree/master/jsonp
window.onload = function(){
var callbackMethod = 'callback_' + new Date().getTime();
var script = document.createElement('script');
script.src = 'https://jsonplaceholder.typicode.com/users/1?callback='+callbackMethod;
document.body.appendChild(script);
window[callbackMethod] = function(data){
delete window[callbackMethod];
document.body.removeChild(script);
console.log(data);
}
}
/**
* Get JSONP data for cross-domain AJAX requests
* @private
* @link http://cameronspear.com/blog/exactly-what-is-jsonp/
* @param {String} url The URL of the JSON request
* @param {String} callback The name of the callback to run on load
*/
var loadJSONP = function ( url, callback ) {
// Create script with url and callback (if specified)
var ref = window.document.getElementsByTagName( 'script' )[ 0 ];
var script = window.document.createElement( 'script' );
script.src = url + (url.indexOf( '?' ) + 1 ? '&' : '?') + 'callback=' + callback;
// Insert script tag into the DOM (append to <head>)
ref.parentNode.insertBefore( script, ref );
// After the script is loaded (and executed), remove it
script.onload = function () {
this.remove();
};
};
/**
* Example
*/
// Function to run on success
var logAPI = function ( data ) {
console.log( data );
}
// Run request
loadJSONP( 'http://api.petfinder.com/shelter.getPets?format=json&key=12345&shelter=AA11', 'logAPI' );
window.document.getElementsByTagName('script')[0];
ไม่document.body.appendChild(…)
?
logAPI
ตั้งค่าเป็นnull
เมื่อเสร็จแล้วจึงสามารถดำเนินการเก็บขยะได้หรือไม่?
หากคุณใช้ ES6 กับ NPM คุณสามารถลองใช้โมดูลโหนด "fetch-jsonp" Fetch API ให้การสนับสนุนสำหรับการโทร JsonP เป็นการเรียก XHR ปกติ
สิ่งที่ต้องมีก่อน: คุณควรใช้isomorphic-fetch
โมดูลโหนดในสแตกของคุณ
เพียงแค่วางคำตอบที่ดีของ sobstel เวอร์ชัน ES6:
send(someUrl + 'error?d=' + encodeURI(JSON.stringify(json)) + '&callback=c', 'c', 5)
.then((json) => console.log(json))
.catch((err) => console.log(err))
function send(url, callback, timeout) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
let timeout_trigger = window.setTimeout(() => {
window[callback] = () => {}
script.parentNode.removeChild(script)
reject('No response')
}, timeout * 1000)
window[callback] = (data) => {
window.clearTimeout(timeout_trigger)
script.parentNode.removeChild(script)
resolve(data)
}
script.type = 'text/javascript'
script.async = true
script.src = url
document.getElementsByTagName('head')[0].appendChild(script)
})
}