动态脚本标签与RESTful服务框架解析
1. 动态脚本标签与JSONP
1.1 动态脚本标签的使用
在Web开发中,我们有时需要动态地向页面中添加脚本标签来获取数据。传统的示例中,脚本标签的URI往往是硬编码的,缺乏灵活性。但JavaScript允许我们向表示当前HTML页面的DOM对象中添加新标签,脚本标签也不例外。
我们可以使用JavaScript编写自定义的脚本标签并插入到文档中,浏览器在处理脚本时会自动加载其
src
属性指定的URI。即使
src
指向的是外部域名,浏览器也允许这样做。这意味着我们可以使用JavaScript向任何提供更多JavaScript代码的URI发送请求并运行代码。
1.2 JSONP的安全问题
虽然这种方式可行,但它存在严重的安全隐患。与使用
XMLHttpRequest
从外部站点获取数据相比,JSONP更加危险。
XMLHttpRequest
最坏的情况也只是发起一个HTTP请求并将XML解析为树形数据结构,而JSONP会发起HTTP请求并运行未知的JavaScript代码,就好像这些代码是我们原始程序的一部分。
恶意的Web服务可能会提供窃取用户Cookie的JavaScript代码,或者在运行承诺的代码时弹出大量广告窗口。由于Ajax对最终用户隐藏了HTTP请求 - 响应周期,这会让用户误以为是我们的网站出了问题。
此外,从REST的角度来看,JSONP也是一种糟糕的策略。它迫使我们使用功能受限的客户端,因为
XMLHttpRequest
支持HTTP的所有特性,而JSONP只能发起GET请求,无法发送请求头、查看响应代码或头信息,也无法处理JavaScript代码以外的表示格式。
1.3 更安全的资源引用方式
引用
src
属性中的新对象的底层技术在用于获取自定义生成的JavaScript以外的资源时更加安全。除了
script
标签,
img
和
frame
等标签也可以让浏览器加载资源。例如,Google Maps使用
img
标签而不是
XMLHttpRequest
调用来获取地图切片图像,其JavaScript代码只是创建
img
标签,让浏览器自动发起请求。
1.4 库支持
Jason Levitt编写了一个名为
JSONscriptRequest
的JavaScript类,使得JSONP的使用变得简单。这个类的工作方式类似于
XMLHttpRequest
,但支持的HTTP特性较少,并且期望服务器返回一段JavaScript代码。
以下是一个动态实现的Yahoo!图像搜索Ajax应用的示例:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/transitional.dtd">
<!--yahoo-ajax-dynamic.html-->
<!--An Ajax application that uses dynamic SCRIPT tags to interactively
fetch data from Yahoo! Web Services and call predefined functions
on that data.-->
<html>
<head><title>Javascript Yahoo! JSON - Dynamic</title></head>
<body>
<h1>Javascript Yahoo! JSON example with dynamic SCRIPT tags</h1>
<form onsubmit="callYahoo(); return false;">
What would you like to see? <input id="query" type="text" /><br />
<input type="submit" value="Fetch pictures from Yahoo! Image Search"/>
</form>
<div id="images">
</div>
<script type="text/javascript">
function formatImages(result)
{
// First clear out any old images.
var images = document.getElementById("images");
while (images.firstChild)
{
images.removeChild(images.firstChild);
}
items = result["ResultSet"]["Result"];
for (var i = 0; i < items.length; i++)
{
image = items[i];
// Create a link
var link = document.createElement("a");
link.setAttribute("href", image["ClickUrl"]);
// Put a thumbnail image in the link.
var img = document.createElement("img");
var thumbnail = image["Thumbnail"];
img.setAttribute("src", thumbnail["Url"]);
img.setAttribute("width", thumbnail["Width"]);
img.setAttribute("height", thumbnail["Height"]);
img.setAttribute("title", image["Height"]);
link.appendChild(img);
images.appendChild(link);
}
}
</script>
<script type="text/javascript" src="jsr_class.js"></script>
<script type="text/javascript">
function callYahoo()
{
var query = document.getElementById("query").value;
var uri = "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch" +
"?query=" + escape(query) +
"&appid=restbook&output=json&callback=formatImages";
alert(uri);
var request = new JSONscriptRequest(uri);
request.buildScriptTag();
request.addScriptTag();
}
</script>
</body>
</html>
在这个示例中,我们通过
JSONscriptRequest
对象发起请求,将资源的URI传递给它。
addScriptTag
方法会将新的脚本标签插入到DOM中,浏览器处理该标签时会发起GET请求并运行返回的JavaScript代码。我们在URI的查询字符串中指定了
callback=formatImages
,这样Yahoo!会返回调用
formatImages
函数的JavaScript代码。
1.5 Dojo库的支持
Dojo库提供了
dojo.io.SrcScript
传输类和
dojo.io.IframeIO
类,使得脚本技巧的使用更加方便。
dojo.io.SrcScript
类使用了类似的脚本标签技巧,而
dojo.io.IframeIO
类则使用了
iframe
标签。这种技巧需要服务器的配合,但它的优点是不会自动将响应文档作为代码执行。
2. RESTful服务框架
2.1 RESTful服务框架的兴起
随着REST设计理念越来越受欢迎,新的框架不断涌现,使得RESTful设计变得更加容易。现有的框架也逐渐增加了RESTful模式和功能,这进一步推动了对REST的关注。
2.2 Ruby on Rails
2.2.1 Rails的简化假设
Ruby on Rails的成功得益于其简化假设。它不像其他框架那样提供大量工具来完成各种任务,而是提供一种方式来完成多种常见任务。如果我们想从关系型数据库中暴露数据,并且数据库表具有特定的名称和结构,同时采用Model - View - Controller架构,那么创建Rails应用会非常快速。
早期版本的Rails采用了REST - RPC混合架构,而Rails 1.2则更加注重RESTful设计。HTTP的统一接口也是一种简化假设,我们可以使用Rails用很少的代码创建复杂的RESTful服务。
2.2.2 路由
当HTTP请求到来时,Rails会分析请求的URI并将请求路由到合适的控制器类。
config/routes.rb
文件告诉Rails如何处理特定的请求。以下是一个简单的
routes.rb
文件示例:
# routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :weblogs do |weblog|
weblog.resources :entries
end
end
这个文件定义了两个控制器类:
WeblogsController
和
EntriesController
,并告诉Rails如何将请求路由到这些类。
WeblogsController
处理
/weblogs
和
/weblogs/{id}
的请求,
EntriesController
处理
/weblogs/{weblog_id}/entries
和
/weblogs/{weblog_id}/entries/{id}
的请求。
2.2.3 资源、控制器和视图
每个Rails控制器可能会暴露两种类型的资源:单个的“列表”或“工厂”资源,响应GET和/或POST请求;以及大量的“对象”资源,响应GET、POST和/或DELETE请求。列表资源通常对应数据库表,对象资源对应表中的行。
Rails为每个控制器定义了五个标准方法,并通过HTTP GET暴露两个特殊的视图模板。以下是
map.resources :weblogs
对应的七个HTTP请求示例:
| 请求方法 | URI | 说明 | 调用方法/渲染视图 |
| ---- | ---- | ---- | ---- |
| GET | /weblogs | 获取博客列表 |
WeblogsController#index
|
| GET | /weblogs/new | 获取创建新博客的表单 |
app/view/welogs/new.rhtml
|
| POST | /weblogs | 创建新博客 |
WeblogsController#create
|
| GET | /weblogs/{id} | 获取单个博客 |
WeblogsController#show
|
| GET | /weblogs/{id};edit | 获取编辑博客状态的表单 |
app/view/welogs/edit.rhtml
|
| PUT | /weblogs/{id} | 更改博客状态 |
WeblogsController#update
|
| DELETE | /weblogs/{id} | 删除博客 |
WeblogsController#delete
|
2.2.4 输出表示
Rails可以根据客户端的请求轻松发送资源的不同表示形式。以下是一个示例代码,展示了如何根据客户端请求的URI或
Accept
头信息返回不同的表示形式:
respond_to do |format|
format.html { render :template => 'weblogs/show' }
format.xml { render :xml => weblog.to_xml }
format.png { render :text => weblog.generate_image,
:content_type => "image/png" }
end
常见的表示格式包括HTML和ActiveResource XML序列化格式。我们可以使用Rails视图来表达HTML表示,通过调用
to_xml
方法将ActiveRecord对象暴露为XML文档。
2.2.5 输入表示
Rails的工作是将传入的表示转换为键值对,并通过
params
哈希表提供这些键值对。默认情况下,它可以解析浏览器发送的表单编码文档和简单的XML文档。如果我们想处理自己的传入表示,可以向
ActionController::Base.param_parsers
哈希表中添加新的
Proc
对象。
2.2.6 作为Web服务的Web应用
Rails 1.2很好地融合了人类Web和可编程Web。它自带的
scaffold_resource
代码生成器可以将数据库表暴露为一组资源。我们可以使用Web浏览器或Web服务客户端(如ActiveResource)来访问这些资源。
使用Web浏览器访问时,我们会得到数据库对象的HTML表示和用于操作它们的HTML表单;使用Web服务客户端访问时,我们会得到数据库对象的XML表示。
2.2.7 Rails/ROA设计流程
以下是Rails/ROA的设计流程:
1. 确定数据集。
2. 将数据集分配给控制器。
- 对于每个控制器:
- a. 该控制器是否暴露列表或工厂资源?
- b. 该控制器是否暴露一组对象资源?
- c. 该控制器是否暴露创建表单或编辑表单资源?
- 对于列表和对象资源:
- 设计与Rails标准不同的客户端接受的表示形式。
- 设计提供给客户端的表示形式。
- 将此资源与现有资源连接起来。
- 考虑典型的事件流程:应该发生什么?
- 考虑错误条件:可能会出现什么问题?
2.3 Restlet
Restlet项目(http://www.restlet.org)提供了一个轻量级但全面的框架,用于将REST概念映射到Java类。它可以用于实现RESTful服务,为Java开发者提供了一种方便的方式来构建RESTful应用程序。
综上所述,动态脚本标签和RESTful服务框架在Web开发中都有着重要的作用。动态脚本标签可以帮助我们动态获取数据,但需要注意安全问题;而RESTful服务框架则可以让我们更轻松地设计和实现RESTful服务。在实际开发中,我们需要根据具体需求选择合适的技术和框架。
2.3 Restlet
Restlet 项目(http://www.restlet.org)为 Java 开发者提供了一个轻量级却功能全面的框架,用于将 REST 概念映射到 Java 类。借助 Restlet,开发者能够轻松实现 RESTful 服务。
2.3.1 Restlet 的优势
Restlet 的优势显著,它具有轻量级的特点,不会给项目带来过多的负担。同时,它全面支持 REST 概念,能让开发者按照 REST 架构风格进行开发。以下是 Restlet 的主要优势:
| 优势 | 说明 |
| ---- | ---- |
| 轻量级 | 对系统资源的占用较少,提高应用性能 |
| 全面性 | 完整支持 REST 架构风格的各个方面 |
| 灵活性 | 可根据不同需求进行定制开发 |
2.3.2 Restlet 的使用示例
以下是一个简单的 Restlet 使用示例,展示如何创建一个基本的 RESTful 服务:
import org.restlet.Application;
import org.restlet.Component;
import org.restlet.Restlet;
import org.restlet.data.Protocol;
import org.restlet.routing.Router;
public class MyRestletApplication extends Application {
@Override
public synchronized Restlet createInboundRoot() {
Router router = new Router(getContext());
// 定义路由规则
router.attach("/resource", ResourceServerResource.class);
return router;
}
public static void main(String[] args) throws Exception {
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
// 添加应用
component.getDefaultHost().attach(new MyRestletApplication());
// 启动组件
component.start();
}
}
在上述代码中,我们创建了一个
MyRestletApplication
类,继承自
Application
。在
createInboundRoot
方法中,我们使用
Router
定义了路由规则,将
/resource
路径映射到
ResourceServerResource
类。在
main
方法中,我们创建了一个
Component
,并将其绑定到 HTTP 协议的 8182 端口,然后启动该组件。
2.4 三种框架的对比
为了更好地选择适合自己项目的框架,我们对 Ruby on Rails、Restlet 和 Django 进行对比,以下是它们的主要特点对比:
| 框架 | 语言 | 特点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| Ruby on Rails | Ruby | 简化假设,开发速度快,适合快速搭建 Web 应用 | 小型 Web 应用、快速迭代项目 |
| Restlet | Java | 轻量级,全面支持 REST 概念 | 企业级 Java 应用、对性能要求高的项目 |
| Django | Python | 功能强大,自带多种工具和功能 | 大型 Web 应用、需要快速开发的项目 |
2.5 选择合适的框架
在选择框架时,我们需要考虑多个因素,以下是选择框架的流程图:
graph TD;
A[确定项目需求] --> B{项目规模};
B -->|小型项目| C[考虑 Ruby on Rails];
B -->|大型项目| D{开发语言偏好};
D -->|Java| E[考虑 Restlet];
D -->|Python| F[考虑 Django];
C --> G[评估开发速度和便捷性];
E --> H[评估性能和稳定性];
F --> I[评估功能和扩展性];
G --> J[做出选择];
H --> J;
I --> J;
根据上述流程图,我们可以按照以下步骤选择合适的框架:
1. 确定项目需求,包括项目规模、功能需求等。
2. 根据项目规模判断是小型项目还是大型项目。
- 如果是小型项目,可以考虑 Ruby on Rails,评估其开发速度和便捷性。
- 如果是大型项目,根据开发语言偏好选择。
- 若偏好 Java,考虑 Restlet,评估其性能和稳定性。
- 若偏好 Python,考虑 Django,评估其功能和扩展性。
3. 综合评估后做出选择。
3. 总结与展望
3.1 总结
动态脚本标签在 Web 开发中是一种获取数据的有效方式,如 JSONP 可以通过动态插入脚本标签实现跨域数据请求。但它存在严重的安全隐患,使用时需要谨慎。同时,一些库如
JSONscriptRequest
和 Dojo 库为动态脚本标签的使用提供了便利。
RESTful 服务框架的兴起使得 RESTful 设计变得更加容易。Ruby on Rails 通过简化假设实现快速开发,Restlet 为 Java 开发者提供了轻量级且全面的 REST 支持,Django 则以其强大的功能和丰富的工具适用于大型 Python 项目。
3.2 展望
随着 Web 技术的不断发展,动态脚本标签和 RESTful 服务框架也将不断演进。在安全方面,未来可能会出现更安全的跨域数据请求方式,解决动态脚本标签的安全问题。在框架方面,各个框架可能会进一步优化,提供更多的功能和更好的性能,以满足不断增长的 Web 应用需求。同时,不同框架之间可能会相互借鉴,融合彼此的优点,为开发者提供更加统一和高效的开发体验。
在实际应用中,开发者需要不断学习和掌握这些技术,根据项目的具体需求选择合适的方法和框架,以开发出高质量、高性能的 Web 应用。
超级会员免费看
779

被折叠的 条评论
为什么被折叠?



