使用jQuery和YQL,以Ajax方式載入外部內容
我們來看看怎樣使用jQuery,以Ajax方式載入外部(其他域上)的內容。這裡的所有程式碼都可以從GitHub下載,也可以在這個演示頁面中獲取,因而不用複製貼上了。
OK,Ajax通過jQuery是很容易做到的,大多數解決方案就幾行程式碼:
$(document).ready(function(){
$('.ajaxtrigger').click(function(){
$('#target').load('ajaxcontent.html');
});
});
檢視這個簡單但有點粗陋的Ajax演示就可以看到結果。
這會將所有帶ajaxtrigger
類的元素轉換成觸發器來載入ajaxcontent.html,並在ID為target
的元素中顯示其內容。
這樣不好,因為多數時候這意味著人們將使用<a
href="#">click me</a>
這種空連結,但這不是我們現在要討論的問題。我在撰寫一篇更長的文章,其中會提到增強Ajax可用性和可訪問性的所有技巧。
要使其能夠重用可以像下面這樣:
$(document).ready(function(){
$('.ajaxtrigger').click(function(){
$('#target').load($(this).attr('href'));
return false;
});
});
這樣,你可以使用<a
href="ajaxcontent.html" class="ajaxtrigger">load some content</a>
來載入內容,而所有JavaScript程式碼都可以重用。
檢視這個可重用Ajax演示就能看到結果。
我要解決的問題發生在點選演示頁面中的第二個連結時:載入外部內容失敗,因為Ajax不允許跨域載入內容。這意味著,<a
href="http://icant.co.uk/" class="ajaxtrigger">see my portfolio</a>
載入Ajax內容將失敗,而且沒有提示。儘管你無數遍地點選這個連結,但是什麼都不會發生。避免出現這種情況的一個方法,是簡單地讓瀏覽器載入該文件,但前提是使用者真的想載入外部連結。
檢視這個允許載入外部連結的演示就能看到結果。
$(document).ready(function(){
$('.ajaxtrigger').click(function(){
var url = $(this).attr('href');
if(url.match('^http')){
return true;
} else {
$('#target').load(url);
return false;
}
});
});
使用PHP代理
如果瀏覽Web,你會發現大多數的解決方案是PHP(或其他語言)代理指令碼。比如,下面是使用cURL的proxy.php代理指令碼:
<?php
$url = $_GET['url'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
echo $content;
?>
然後可以稍作修改使用這個指令碼(使用代理):
$(document).ready(function(){
$('.ajaxtrigger').click(function(){
var url = $(this).attr('href');
if(url.match('^http')){
url = 'proxy.php?url=' + url;
}
$('#target').load(url);
return false;
});
});
用這樣的代理指令碼依舊是個很蠢的辦法,因為不進行過濾,人們就可以使用這個指令碼來載入你伺服器上的任何文件,並將其內容顯示在自己的頁面中(用firebug來重新命名連結,就能看到你伺服器上的任何內容),他們可以使用它將郵件群髮指令碼插入文件,或者簡單地使用它來重定向到任何其他Web資源,並且讓你的伺服器看上去就是傳送請求的那個伺服器。垃圾郵件製造者就有了施展才華的地方了。
使用白名單和過濾代理
因而,要想使用代理,就得確保有被認可的URI的白名單。此外,除了另一個HTML文件的主體,其他的都除去比較好。另一個好辦法是過濾指令碼。這會避免顯示錯誤和執行你本不想在網站上執行的指令碼。
就像下面這樣:
<?php
$url = $_GET['url'];
$allowedurls = array(
'http://developer.yahoo.com',
'http://icant.co.uk'
);
if(in_array($url,$allowedurls)){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
$content = preg_replace('/.*<body[^>]*>/msi','',$output);
$content = preg_replace('/</body>.*/msi','',$content);
$content = preg_replace('/<?/body[^>]*>/msi','',$content);
$content = preg_replace('/[r|n]+/msi','',$content);
$content = preg_replace('/<--[Ss]*?-->/msi','',$content);
$content = preg_replace('/<noscript[^>]*>[Ss]*?</noscript>/msi','',$content);
$content = preg_replace('/<script[^>]*>[Ss]*?</script>/msi','',$content);
$content = preg_replace('/<script.*/>/msi','',$content);
echo $content;
} else {
echo 'Error: URL not allowed to load here.';
}
?>
使用YQL的純JavaScript解決方案
但是,如果沒有權利訪問伺服器,或者你只想使用JavaScript,怎麼辦?不用擔心,這是可以做到的。藉助YQL可以載入任何HTML文件,並以JSON格式返回。jQuery具有載入JSON的好介面,因此與YQL一起使用就可以達到我們的目的。
從YQL獲取HTML很容易,使用下面語句即可:
select * from html where url="http://icant.co.uk"
YQL還可以完成下面一些事:
- 載入並清理HTML文件
- 使用HTML Tidy執行HTML文件來刪除不好的標記
- 快取HTML
- 只返回HTML的主體內容,因而除內聯樣式外不需處理其他樣式
資料輸出格式可以是XML或JSON。如果為JSON定義了回撥引數,就表明要使用JSON-P,所有HTML都會儲存在一個JavaScript物件中——這不適合重組。
foo({
"query":{
<a href=""1" title="">count</a>",
<a href=""2010-01-10T07:51:43Z" title="">created</a>",
<a href=""en-US" title="">lang</a>",
<a href=""2010-01-10T07:51:43Z" title="">updated</a>",
<a href=""http://query.yahoo[...whatever...]k%22" title="">uri</a>",
"results":{
"body":{
"div":{
<a href=""doc2" title="">id</a>",
<a href="[{"id":"hd" title="">div</a>",
<a href=""icant.co.uk" title="">h1</a> - everything Christian Heilmann"
},
{<a href=""bd" title="">id</a>",
"div":[
{<a href="[{"h2":"About" title="">div</a> this and me","[... and so on...]
}}}}}}}});
當定義了帶XML輸出的回撥時,會得到將HTML資料作為陣列中字串的函式呼叫,簡單多了:
foo({
"query":{
<a href=""1" title="">count</a>",
<a href=""2010-01-10T07:47:40Z" title="">created</a>",
<a href=""en-US" title="">lang</a>",
<a href=""2010-01-10T07:47:40Z" title="">updated</a>",
<a href=""http://query.y[...who" title="">uri</a> cares...]%22"},
"results":[
"<body>n <div id="doc2">n <div id="hd">n
<h1>icant.co.uk - everything Christian Heilmann</h1>n
... and so on ..."
]
});
使用jQuery的getJSON()
方法,訪問YQL端點,這很容易實現:
$.getJSON("http://query.yahooapis.com/v1/public/yql?"+
"q=select%20*%20from%20html%20where%20url%3D%22"+
encodeURIComponent(url)+
"%22&format=xml'&callback=?",
function(data){
if(data.results[0]){
var data = filterData(data.results[0]);
container.html(data);
} else {
var errormsg = '<p>Error: could not load the page.</p>';
container.html(errormsg);
}
}
);
組合在一起可以得到使用jQuery和YQL的跨域Ajax解決方案:
$(document).ready(function(){
var container = $('#target');
$('.ajaxtrigger').click(function(){
doAjax($(this).attr('href'));
return false;
});
function doAjax(url){
// 如果它是個外部URI
if(url.match('^http')){
// 呼叫YQL
$.getJSON("http://query.yahooapis.com/v1/public/yql?"+
"q=select%20*%20from%20html%20where%20url%3D%22"+
encodeURIComponent(url)+
"%22&format=xml'&callback=?",
// 這個函式得到的資料來自成功的JSON-P呼叫
function(data){
// 如果有資料,過濾它並呈現出來
if(data.results[0]){
var data = filterData(data.results[0]);
container.html(data);
// 否則提示出錯了
} else {
var errormsg = '<p>Error: could not load the page.</p>';
container.html(errormsg);
}
}
);
// 如果它不是外部URI,使用Ajax的load()方法
} else {
$('#target').load(url);
}
}
// 過濾掉一些不好的東西
function filterData(data){
data = data.replace(/<?/body[^>]*>/g,'');
data = data.replace(/[r|n]+/g,'');
data = data.replace(/<--[Ss]*?-->/g,'');
data = data.replace(/<noscript[^>]*>[Ss]*?</noscript>/g,'');
data = data.replace(/<script[^>]*>[Ss]*?</script>/g,'');
data = data.replace(/<script.*/>/,'');
return data;
}
});
當然,這個例子還很粗糙。實際的Ajax解決方案應該考慮超時,以及未找到文件的情況。檢視帶載入指示器、異常處理和黃褪技術的完整程式碼以獲得靈感。
相關文章
- jQuery load()方法載入指定檔案內容jQuery
- 對於動態載入內容 (包括 Ajax 請求內容) 繫結點選事件事件
- Shell指令碼匯入外部指令碼內容指令碼
- 使用jQuery 完成ajax 檔案下載jQuery
- jQuery文字框輸入內容同步jQuery
- jQuery入門(五)Ajax和jsonjQueryJSON
- Jquery 和 Ajax的 使用方法jQuery
- jQuery根據滾動條位置載入相應的內容jQuery
- Webview 載入文章內容WebView
- ajax載入xml檔案內容程式碼例項簡單介紹XML
- php原生上拉載入,點選載入更多(jQuery,ajax,mysql)PHPjQueryMySql
- JQuery使用AJAXjQuery
- jquery的ajax的資料載入詳解jQuery
- 使用promise封裝jquery的ajax來實現async和await方式Promise封裝jQueryAI
- 使用 Oracle Data Pump 解除安裝和載入資料庫內容Oracle資料庫
- jQuery文字框內容輸入同步功能jQuery
- jQuery - 設定內容和屬性jQuery
- jQuery - 獲取內容和屬性jQuery
- Ajax程式碼執行前應該先載入jQueryjQuery
- jquery製作圖片瀑布流點選按鈕載入更多內容jQuery
- JQuery Ajax通過Handler訪問外部XML資料jQueryXML
- 以後的內容......
- jQuery的ajax和json使用例項jQueryJSON
- 使用sqlloader的直接載入方式和傳統載入方式的效能差異SQL
- jquery實現的設定指定元素的文字內容和html內容jQueryHTML
- 使用 jQuery Ajax 在頁面滾動時從伺服器載入資料jQuery伺服器
- jquery ajax簡單使用jQuery
- Jquery如何獲取和設定元素內容?jQuery
- 使用jquery清空指定元素中的所有內容jQuery
- jQuery ajax載入完畢再去執行後面的程式碼jQuery
- jquery ajax方式直接提交整個表單jQuery
- jQuery Validate非同步ajax方式驗證jQuery非同步
- jQuery動態載入更新外部樣式表程式碼例項jQuery
- 使用jQuery載入js指令碼jQueryJS指令碼
- jQuery – AJAX get() 和 post() 方法jQuery
- jQuery學習(2)ajax()使用jQuery
- AJAX+json+jquery實現預載入瀑布流佈局JSONjQuery
- Laravel 中使用 puppeteer 採集非同步載入的網頁內容Laravel非同步網頁