jsonp原理及使用
初識(shí)jsonp
jsonp 全稱是JSON with Padding,是為了解決跨域請(qǐng)求資源而產(chǎn)生的解決方案。很多時(shí)候我們需要在客戶端獲取服務(wù)器數(shù)據(jù)進(jìn)行操作,一般我們會(huì)使用ajax+webservice做此事,但是如果我們希望獲取的數(shù)據(jù)和當(dāng)前頁(yè)面并不是一個(gè)域,著名的同源策略(不同域的客戶端腳本在沒(méi)明確授權(quán)的情況下,不能讀寫對(duì)方的資源)會(huì)因?yàn)榘踩驔Q絕請(qǐng)求,也就是我們不能向其它域直接發(fā)送請(qǐng)求以獲取資源。
在localhot域上有一個(gè)books.php,里面包含腳本對(duì)test.com域的books.php發(fā)送get請(qǐng)求,希望獲取其book列表資源,這就是一個(gè)跨域請(qǐng)求資源
$.ajax({
type:'get',
url:'http://test.com/books.php'
});
頁(yè)面會(huì)報(bào)一個(gè)這樣的錯(cuò)誤:XMLHttpRequest cannot load http://test.com/books.php. Origin http://localhost is not allowed by Access-Control-Allow-Origin.jsonp是為了解決這個(gè)問(wèn)題出現(xiàn)的。
jsonp原理
雖然有同源策略的限制,但是并不是HTML上所有資源都必須是同一個(gè)域的,我們常見(jiàn)的頁(yè)面為了節(jié)省流量或加載速度采用Google或微軟的 jQuery CDN,在頁(yè)面上我們可以這樣寫就可以引用jQuery了
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
</script>
iframe、img、style、script等元素的src屬性可以直接向不同域請(qǐng)求資源,jsonp正式利用script標(biāo)簽跨域請(qǐng)求資源的
簡(jiǎn)單實(shí)現(xiàn)
localhost的books.php希望獲得域test.com的books列表,在域test.com內(nèi)book列表存儲(chǔ)在books.xml中
test.com/books.xml
<?xml version="1.0"?>
<books>
<book name="JavaScript: The Defiitive Guide" publisher="O'Reilly Media, Inc.">
<author>David Flanagan</author>
</book>
<book name="PHP anf MySQL Web Development" publisher="Perason Education">
<author>Luke Welling</author>
<author>Laura Thomson</author>
</book>
<book name="HTTP: The Defiitive Guide" publisher="O'Reilly Media, Inc.">
<author>David Courley</author>
<author>Brian Totty</author>
</book>
</books>
明顯JavaScript不能直接獲取books.xml,在test.com中需要有一個(gè)機(jī)制將xml轉(zhuǎn)化為json(這也就是為什么叫jsonp,其實(shí)和ajax一樣,返回的數(shù)據(jù)不一定是json格式,只是json很好用),并動(dòng)態(tài)拼接一條javascript調(diào)用語(yǔ)句返回,這個(gè)例子中直接使用php頁(yè)面拼接
test.com/bookservice.php
<?php
$path=$_SERVER["DOCUMENT_ROOT"].'/books.xml';
$json=json_encode(simplexml_load_file($path));
$callbackFn=$_GET['callback'];
echo "$callbackFn($json);";
?>
這樣首先把xml文件內(nèi)容轉(zhuǎn)換成一個(gè)json對(duì)象
{"book":[
{"@attributes":{"name":"JavaScript: The Defiitive Guide","publisher":"O'Reilly Media, Inc."},"author":"David Flanagan"},
{"@attributes":{"name":"PHP anf MySQL Web Development","publisher":"Perason Education"},"author":["Luke Welling","Laura Thomson"]},
{"@attributes":{"name":"HTTP: The Defiitive Guide","publisher":"O'Reilly Media, Inc."},"author":["David Courley","Brian Totty"]}
]}
然后拼接為一條javascript語(yǔ)句交給localhost去處理,當(dāng)然test.com并不知道應(yīng)該拼接的方法名叫什么,需要localhost在發(fā)送請(qǐng)求的時(shí)候在url中傳入一個(gè)叫callback(這個(gè)也隨便,兩邊同步就行)的參數(shù)指明。看看localhost怎么發(fā)送請(qǐng)求吧
localhost/books.php
<!DOCTYPE html>
<html>
<head>
<title>Books</title>
<?php include('/components/headerinclude.php');?></head>
<style type="text/css">
.book-title
{
font-size: 15px;
font-weight:bold;
margin-top:6px;
}
.book-info
{
color:#ccc;
font-style:italic;
border-bottom:dashed 1px #ccc;
}
</style>
</head>
<body>
<div style="margin:20px;">
<div style="font-size:16px;font-weight:bold;">Books</div>
<div id="books">
</div>
</div>
</body>
</html>
我們希望在id為books的div中展示所有book,先添加一個(gè)用以顯示book的javascript函數(shù),也就是獲取到數(shù)據(jù)后的回調(diào)函數(shù),結(jié)合上面拼接的json格式可以這么寫
function displayBooks(books){
var books=books.book;
var booksContainer=document.getElementById('books');
for(var i=0;i<books.length;i++){
var tmp=Array();
tmp.push('<div class="book-title">'+books[i]['@attributes'].name+'</div>');
tmp.push('<div class="book-info">');
tmp.push('<div>Publisher: '+books[i]['@attributes'].publisher+'</div>');
tmp.push('<div>Author(s): ');
if(typeof books[i].author=='string'){
tmp.push(books[i].author);
}else{
var authors=books[i].author;
for(var j=0;j<authors.length;j++){
tmp.push(authors[j]+' ');
}
}
tmp.push('</div>'); //end of author
tmp.push('</div>'); //end of book info
booksContainer.innerHTML+=tmp.join('');
}
}
然后是關(guān)鍵的jsonp請(qǐng)求的方法了
function getBooks(){
var script=document.createElement('script');
script.setAttribute('type','text/javascript');
script.setAttribute('src','http://test.com/bookservice.php?callback=displayBooks');
document.body.appendChild(script);
}
getBooks();
在getbooks()方法中動(dòng)態(tài)創(chuàng)建了一個(gè)script標(biāo)簽,設(shè)置其src為test.com提供的獲取數(shù)據(jù)的service接口并傳入回調(diào)函數(shù),這樣我們可以看看頁(yè)面的反應(yīng),在Chrome控制臺(tái)下可以看到這條請(qǐng)求

我們就可以在localhost下獲取test.com的books了

jquery實(shí)現(xiàn)
在jquery中也有對(duì)jsonp的封裝,不過(guò)jquery把其放到了ajax中,不明白為什么,畢竟這東西和ajax不太一樣。寫一個(gè)jQuery版的
function getBooks(){
$.ajax({
type:'get',
url:'http://test.com/bookservice.php',
dataType:'jsonp',
jsonp:'callback',
jsonpCallback:'displayBooks'
});
}
看起來(lái)完全一樣,不過(guò)方便了很多,不用自己創(chuàng)建script標(biāo)簽神馬的了,指明dataType為jsonp,回調(diào)函數(shù)不放在url內(nèi)了,而是使用兩個(gè)參數(shù)分別指明。
安全性問(wèn)題
當(dāng)然使用jsonp會(huì)在一定程度上造成安全性問(wèn)題,如果請(qǐng)求的站點(diǎn)不是新人站點(diǎn),那么可能會(huì)在返回的方法調(diào)用中包含一些惡意代碼。所以盡量向信任的站點(diǎn)發(fā)送請(qǐng)求。另外xss也經(jīng)常會(huì)利用jsonp向站點(diǎn)注入惡意代碼。
相關(guān)文章
前端HTTP發(fā)POST請(qǐng)求攜帶參數(shù)與后端接口接收參數(shù)的實(shí)現(xiàn)
近期在學(xué)習(xí)的時(shí)候,碰到一個(gè)關(guān)于post的小問(wèn)題,故拿出來(lái)分享一下,下面這篇文章主要給大家介紹了關(guān)于前端HTTP發(fā)POST請(qǐng)求攜帶參數(shù)與后端接口接收參數(shù)的相關(guān)資料,需要的朋友可以參考下2022-10-10js實(shí)現(xiàn)動(dòng)態(tài)添加、刪除行、onkeyup表格求和示例
動(dòng)態(tài)添加、刪除行想必大家并不陌生,下面為大家介紹通過(guò)js是如何實(shí)現(xiàn)的,有此需求的朋友可不要錯(cuò)過(guò)了哈2013-08-08D3.js實(shí)現(xiàn)散點(diǎn)圖和氣泡圖的方法詳解
這篇文章將會(huì)給大家介紹了另外兩種可視化圖表,利用D3.js實(shí)現(xiàn)散點(diǎn)圖和氣泡圖,文章通過(guò)多個(gè)方面介紹的非常詳細(xì),下面來(lái)一起看看吧。2016-09-09bootstrap實(shí)現(xiàn)動(dòng)態(tài)進(jìn)度條效果
本篇文章主要介紹了bootstrap實(shí)現(xiàn)動(dòng)態(tài)進(jìn)度條效果,進(jìn)度條可以加強(qiáng)應(yīng)用的用戶體驗(yàn)效果,看到數(shù)字,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03js實(shí)現(xiàn)的仿新浪微博完美的時(shí)間組件升級(jí)版
本博客沒(méi)有華麗的布局,只求樸實(shí)的js的代碼,只為js代碼愛(ài)好者提供,一周大概會(huì)出1-2篇js前沿代碼的文章.只是代碼,不說(shuō)技術(shù)2011-12-12