JQuery是一款不错的Javascript脚本框架,相信园子里的很多朋友对它都不陌生,我们在开发Web应用程序时难免会使用到Javascript脚本,而使用一款不错的脚本框架将会大大节省我们的开发时间, 并可以毫不费力地实现很多非常酷的效果。JQuery的使用非常简单,我们只需要从其官方网站上下载一个脚本文件并引用到页面上即可,然后你就可以在你的脚本代码中任意使用JQuery提供的对象和功能了。
在JQuery中使用Ajax方法异步获取服务器资源非常简单,读者可以参考其官方网站上提供的例子http://api.jquery.com/category/ajax/。当然,作为客户端脚本,JQuery也会遇到跨域访问资源的问题,什么是跨域访问呢?简单来说就是脚本所要访问的资源属于网站外部的资源,脚本所在的位置和资源所在的位置不在同一区域。默认情况下,浏览器是不允许直接进行资源的跨域访问的,除非客户端浏览器有设置,否则访问会失败。在这种情况下,我们一般都会采用在服务器端使用handler来解决,就是说在脚本和资源之间建立一个桥梁,让脚本访问本站点内的handler,通过handler去访问外部资源。这个是非常普遍的做法,而且操作起来也非常简单,因为会经常使用到,所以在此记录一下,方便日后使用!
首先需要在网站中创建一个handler,在Visual Studio中新建一个Generic Handler文件,拷贝下面的代码:
namespace WebApplication1
{
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// Asynchronous HTTP handler for rendering external xml source.
/// </summary>
public class Stock : System.Web.IHttpAsyncHandler
{
private static readonly SafeList safeList = new SafeList();
private HttpContext context;
private WebRequest request;
/// <summary>
/// Gets a value indicating whether the HTTP handler is reusable.
/// </summary>
public bool IsReusable
{
get { return false ; }
}
/// <summary>
/// Verify that the external RSS feed is hosted by a server on the safe list
/// before making an asynchronous HTTP request for it.
/// </summary>
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var u = context.Request.QueryString[ " u " ];
var uri = new Uri(u);
if (safeList.IsSafe(uri.DnsSafeHost))
{
this .context = context;
this .request = HttpWebRequest.Create(uri);
return this .request.BeginGetResponse(cb, extraData);
}
else
{
throw new HttpException( 204 , " No content " );
}
}
/// <summary>
/// Render the response from the asynchronous HTTP request for the RSS feed
/// using the response's Expires and Last-Modified headers when caching.
/// </summary>
public void EndProcessRequest(IAsyncResult result)
{
string expiresHeader;
string lastModifiedHeader;
string rss;
using (var response = this .request.EndGetResponse(result))
{
expiresHeader = response.Headers[ " Expires " ];
lastModifiedHeader = response.Headers[ " Last-Modified " ];
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream, true ))
{
rss = reader.ReadToEnd();
}
}
var output = this .context.Response;
output.ContentEncoding = Encoding.UTF8;
output.ContentType = " text/xml; " ; // "application/rss+xml; charset=utf-8";
output.Write(rss);
var cache = output.Cache;
cache.VaryByParams[ " u " ] = true ;
DateTime expires;
var hasExpires = DateTime.TryParse(expiresHeader, out expires);
DateTime lastModified;
var hasLastModified = DateTime.TryParse(lastModifiedHeader, out lastModified);
cache.SetCacheability(HttpCacheability.Public);
cache.SetOmitVaryStar( true );
cache.SetSlidingExpiration( false );
cache.SetValidUntilExpires( true );
DateTime expireBy = DateTime.Now.AddHours( 1 );
if (hasExpires && expires.CompareTo(expireBy) <= 0 )
{
cache.SetExpires(expires);
}
else
{
cache.SetExpires(expireBy);
}
if (hasLastModified)
{
cache.SetLastModified(lastModified);
}
}
/// <summary>
/// Do not process requests synchronously.
/// </summary>
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException();
}
}
/// <summary>
/// Methods for matching hostnames to a list of safe hosts.
/// </summary>
public class SafeList
{
/// <summary>
/// Hard-coded list of safe hosts.
/// </summary>
private static readonly IEnumerable < string > hostnames = new string []
{
" cnblogs.com " ,
" msn.com " ,
" 163.com " ,
" csdn.com "
};
/// <summary>
/// Prefix each safe hostname with a period.
/// </summary>
private static readonly IEnumerable < string > dottedHostnames =
from hostname in hostnames
select string .Concat( " . " , hostname);
/// <summary>
/// Tests if the <paramref name="hostname" /> matches exactly or ends with a
/// hostname from the safe host list.
/// </summary>
/// <param name="hostname"> Hostname to test </param>
/// <returns> True if the hostname matches </returns>
public bool IsSafe( string hostname)
{
return MatchesHostname(hostname) || MatchesDottedHostname(hostname);
}
/// <summary>
/// Tests if the <paramref name="hostname" /> ends with a hostname from the
/// safe host list.
/// </summary>
/// <param name="hostname"> Hostname to test </param>
/// <returns> True if the hostname matches </returns>
private static bool MatchesDottedHostname( string hostname)
{
return dottedHostnames.Any(host => hostname.EndsWith(host, StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>
/// Tests if the <paramref name="hostname" /> matches exactly with a hostname
/// from the safe host list.
/// </summary>
/// <param name="hostname"> Hostname to test </param>
/// <returns> True if the hostname matches </returns>
private static bool MatchesHostname( string hostname)
{
return hostnames.Contains(hostname, StringComparer.InvariantCultureIgnoreCase);
}
}
}
我给出的例子中是想通过Ajax异步取得msn站点上微软的股票信息,其外部资源地址为http://money.service.msn.com/StockQuotes.aspx?symbols=msft,我们在页面上这样使用JQuery api通过Handler来访问数据:
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title ></ title >
< script type ="text/javascript" src ="jquery-1.3.2.min.js" ></ script >
</ head >
< body >
< div id ="con" >
< span id ="loader" > loading... </ span >
</ div >
< script type ="text/javascript" >
function getData() {
$( " #loader " ).ajaxStart( function () {
$( this ).show();
});
$( " #loader " ).ajaxComplete( function () {
$( this ).hide();
});
$.ajax({
type: " GET " ,
url: " Stock.ashx?u=http://money.service.msn.com/StockQuotes.aspx?symbols=msft " ,
dataType: " xml " ,
success: function (data) {
var last = "" ;
var change = "" ;
var percentchange = "" ;
var volume = "" ;
var cap = "" ;
var yearhigh = "" ;
var yearlow = "" ;
$(data).find( ' ticker ' ).each( function () {
last = $( this ).attr( ' last ' );
change = $( this ).attr( ' change ' );
percentchange = $( this ).attr( ' percentchange ' );
volume = $( this ).attr( ' volume ' );
cap = $( this ).attr( ' marketcap ' );
yearhigh = $( this ).attr( ' yearhigh ' );
yearlow = $( this ).attr( ' yearlow ' );
document.getElementById( ' con ' ).innerHTML = ' <span>name: ' + last + ' high: ' + volume + ' low: ' + cap + ' </span> ' ;
})
}
});
}
$(window).load(getData);
</ script >
</ body >
</ html >
下面是实现的结果:
name:25.8 high:67,502,221 low:$226,107,039,514
Handler的写法基本都大同小异,因此可以写成一个通用的例子,以后如遇到在脚本中需要跨域访问资源时便可以直接使用!代码记录于此,方便查阅。