想知道Tim O'Reilly(技术领袖)与Alfred Chuang (BEA CEO)之间的聚合(mushup)会是怎样吗?我想这可能没有什么亮点,但是O'Reilly Safari与BEA dev2dev之间的聚合应该会具有更大的吸引力。会不会是将一个世界级的在线技术库(Safari)嵌入世界级企业开发人员Web站点(dev2dev)呢?这听起来似乎不错。在本文中,我将展示如何使用基于浏览器的的聚合工具Greasemonkey来实现这一点。
正如我上一篇blog中演示的,我们可以很容易地操作Web上的任何网站。使这成为可能的工具是Greasemonkey,该工具允许您注入、修改或删除网页片段。所有这些都是在Firefox浏览器的客户端完成的。例如,在 我以前的blog 中,展示了将新的链接添加到dev2dev Web站点是多么容易。在这一示例中,Greasemonkey脚本找到了页面中的正确注入点,然后在该点上注入一个新的链接。
如果您读过Mark Pilgrim的 Dive Into Greasemonkey 在线手册或者他撰写的 Greasemonkey Hacks 一书,那么您会发现所有事情都将使用HTML文档来完成。您可以按任何您想要的方式切分页面。例如,某个脚本编写人员编写了 Ad Blocker 用户脚本,该脚本可以像施展魔术一样从任何页面删除广告。此外,编写用于GMail的Greasemonkey脚本似乎成了 小规模行业。
如果将术语聚合的含义延伸一下,那么您甚至可以将这些活动的结果称为聚合。目标Web站点是使用Greasemonkey用户脚本融合在一起的。但如何创建一个更权威性的聚合呢?该脚本能从另一个站点将元素注入目标web站点吗?再次声明,这用Greasemonkey很容易做到,这篇blog将展示如何实现。
O'Reilly Safari + BEA dev2dev
正如前文中提到的,聚合将以BEA的dev2dev Web站点为目标,与 以前的blog 一样。但在这篇教程中,我将展示如何从另一个站点(O'Reilly的书目)注入动态内容。想法如下:当您在BEA dev2dev站点上阅读关于web技术(JSON、Ajax、JavaScript和Greasemonkey等)的blog和文章时,那么有一个链接到O'Reilly书目的嵌入式链接列表将会是一个不错的主意。如果希望找到一本关于您在blog或文章中所见技术的更多学习内容的书籍,那么这会很有帮助。此外,此列表将包含链接到 O'Reilly Safari 在线图书馆的链接,为您提供对关于该主题的更深层书籍和论文的即时访问。Safari减少了通过邮件订购O'Reilly书籍的需要——几乎整个O'Reilly目录都可以很方便地用于在线阅读。
BEA dev2dev目前还没有这项O'Reilly功能,但这不是问题。在这篇blog中,我会使用Greasemonkey构建一个聚合,来创建此功能。
让我们开始吧……
使用Greasemonkey 构建一个Web
我假定您已经阅读过 我以前的blog 并了解以下内容:
什么是Greasemonkey,以及它如何在不改动目标站点的情况下在Firefox浏览器中施展其魔法
如何将HTML注入web页面上的某个地址
基本熟悉一门编程语言,比如Java、JavaScript等
此外,需要大致了解什么是XmlHttpRequest,我会对其进行介绍。XmlHttpRequest是Ajax buzzword的核心和灵魂,您可能已经听过有关Ajax buzzword的一些事情。XmlHttpRequest允许浏览器根据JavaScript以编程的方式发出HTTP请求。XmlHtutpReqest在页面上悄悄进行幕后操作,收集来自web服务器的信息。此特性与代码一起用来修改当前页面(称为DOM操作),以更新小部分页面,而不会造成整个页面刷新。这就是Ajax。如果您想了解更多,在dev2dev上有关于该主题的详细描述文章,比如 David Teare撰写的这篇文章。
若要构建O'Reilly Safari + BEA dev2dev的聚合,那么XmlHttpRequest将成为解决方案的基础。当用户浏览dev2dev上的一篇blog或文章时,Greasemonkey脚本会将一个XmlHttpRequest发送到O'Reilly的Web站点,以收集相关书籍的列表。它会将blog或文章的标题作为搜索查询传递,并且指定只期望结果集中出现三本书。一旦收到响应,Greasemonkey脚本会提取这三本书的摘要,并将该列表注入blog或文章中。
作为起点,让我们来看一下我在dev2dev上的一篇聚合教程:Mashup Article。现在,请观察下图,查看注入O'Reilly链接的聚合的最终结果:

单源策略(Single Origin Policy)
如果您通过阅读了解过一般意义上的聚合或专门了解过XmlHttpRequest,那么您可能看出上述计划中存在一个问题。浏览器实现了一个影响XmlHttpRequest的安全策略。此策略叫做Single Origin Policy (SOP),设计用于阻止 Cross-Site-Scripting (XSS) 攻击。XSS的具体描述在这里不是重点,但SOP是。SOP阻止XmlHttpRequest将来自不同于父页面的网络域的URI为目标。例如,如果用户在浏览器的地址栏中键入http://dev2dev.bea.com,那么根据该页面触发的XmlHttpRequest无法以http://hack.evil.com为目标。SOP将XmlHttpRequest限制在bea.com域上。这就是安全性,并且这样做很好。
那么我的实现此聚合的计划如何呢?如果用户的目标是dev2dev.bea.com上的一篇blog或文章,如何能够将一个XmlHttpRequest发送给O'Reilly web属性呢?答案是,Greasemonkey脚本在比普通页面JavaScript更高的一个权限级别上进行操作。SOP并没有应用于从Greasemonkey脚本驱动的XmlHttpRequests。因此,我们显然要取消此聚合实现!

构建脚本
我再次假设您已经阅读过 我以前的blog,并了解Greasemonkey如何将HTML注入页面。我在这里将要展示的是如何将XmlHttpRequest发送到Greasemonkey脚本中的Web站点,如何处理结果,提取所需的信息。然后使用上面已经介绍过的技术将这些信息注入dev2dev blog或文章。以下完整脚本在Greasemonkey脚本存储库上是公开可用的:dev2dev Oreilly Script。我鼓励您查看完整脚本,安装它,并在以后访问dev2dev时使用它。
下面是部分脚本清单。它展示了以下这些元素:
构造URI——设置一个参数,将查询结果限制为3个,并将blog或文章标题设置为书籍查询
对该URI调用XmlHttpRequest,并传递一个回调函数,以便在接收到响应时调用
回调函数解析该响应,并将书籍列表注入页面
// SNIP - code removed for brevity.
// The full script finds the right place in the DOM
// to inject the O'Reilly results
if (commentsAnchor)
{
// build our not-quite-REST URL, not oreilly.com but
// nevertheless it is the O'Reilly book query.
// Note: passing blog title as the query string
var oreillyUrl =
'http://search.atomz.com/search/?sp-a=sp1000a5a9'+
'&sp-t=store&sp-x-1=cat&sp-x-2=cat2&sp-q-2=Books'+
'&sp-c=3&sp-q='+
document.title;
GM_log('URL: '+oreillyUrl);
var user_agent = 'Mozilla/4.0 Greasemonkey';
// go ask Tim what he would recommend based on the
// blog/article title
GM_XmlHttpRequest({
method: 'GET',
url: oreillyUrl,
headers: {
'User-agent': user_agent,
'Accept': 'text/html',
},
onload: processOreillyResponse
});
}
else {
GM_log(' Error: did not find a comment anchor');
}
// callback from the XmlHttpRequest with response
function processOreillyResponse(responseDetails)
{
oreillyHTML = responseDetails.responseText;
// we want to find this HTML in the response since
// it delineates the list of books:
/*
<!-- ResultListStart -->
blah blah
<!-- ResultListEnd -->
*/
var start = oreillyHTML.indexOf(
"<!-- ResultListStart");
var end = oreillyHTML.indexOf(
"<!-- ResultListEnd -->", start);
GM_log("Clipping start: "+start+" end: "+end);
var result = oreillyHTML.substring(start, end-1);
if (result)
{
oreillyHTML = result;
// create the HTML element containing the list
resultsElement = document.createElement(
"placeholder");
resultsElement.innerHTML = oreillyHTML;
// inject the list into the page
commentsAnchor.parentNode.insertBefore(
resultsElement, commentsAnchor);
}
else {
GM_log("Nothing was returned from the clipping");
}
}
将此脚本安装到Firefox中后,Greasemonkey会以适当的方式将O'Reilly书籍结果注入dev2dev页面。此外,将使用链接到传统书目的链接以便利的方式标记从O'Reilly返回的结果,对Safari也将执行相同操作。因此,只需在blog或文章上轻轻一点,您就可以导航到Safari,并畅读dev2dev上关于您刚阅读的技术的完整书籍。
下一个问题:Greasemonkey对企业而言是一个好的聚合解决方案吗?
如果阅读过我的blog,那么您会知道,我喜欢评价如何在企业中使用各种聚合技术。我做了一个与Greasemonkey有关的选择,但有太多的素材值得写。我将在我的下一篇文章中畅谈此话题。实际上,我将讨论如何介绍它——我将在下三篇blog中延伸此讨论,但也有可能我会一次将它写出来。我们需要考虑各种问题,比如版本确认、Greasemonkey的反向安全模型和Greasemonkey的mashup点。订阅我的blog feed,确保您能赶上我将如何打包它的讨论。
此外,请参阅:
dev2dev Oreilly Script – 已完成的O'Reilly Safari + BEA dev2dev Greasemonkey脚本
Using Greasemonkey to weave new features into web sites – 我以前的blog
Dive Into Greasemonkey - Mark Pilgrim的权威性的在线指导
Greasemonkey Hacks - Mark Pilgrim的关于Greasemonkey 的O'Reilly卷
Ajax Introduction – 由David Teare撰写,发表于dev2dev之上
O'Reilly Safari – 最大的技术书籍和文章的在线仓库
原文出处:http://dev2dev.bea.com/blog/plaird/archive/2007/07/oreilly_safari.html