43、动态脚本标签与RESTful服务框架解析

动态脚本标签与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 应用。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值