尽管随着 Android、iOS 和其他移动操作系统的版本不断升级,移动浏览器变得越来越强大,但物理局限仍然存在,比如较小的屏幕和使用触摸作为新输入模式(而不是使用鼠标)。尽管一些智能电话或许可以显示一个网站,但最终的显示结果常常难以使用,甚至完全无用。按钮和其他控件需要调整大小,以便能够通过手指而不是鼠标指针轻松操作它们,而且滑动和多点触摸手势等新动作能被高效地利用。简言之,需要各方齐心协力,才能使这些站点不仅仅是移动友好的,而是支持移动的。
减少的屏幕可用空间和触摸控制是促进简化和重组 Web UI,使 Web 应用程序适用于移动设备的主要因素。尽管可以生成在桌面和移动浏览器上以不同方式呈现的 单一 UI,但此方法通常用于避免对现有 Web 应用程序的任何修改。相反,目标应该是生成一组 静态资产(标记、样式表和 JavaScript代码),它们提供了对 Web 应用程序功能的移动访问,无需以任何方式修改服务器端代码。现有的站点仍然原封不动。
从操作角度讲,这避免了将代码更改部署到生产环境中的高昂成本。它还消除了对在添加移动支持期间修改的现有功能进行回归测试的需求。另外,因为使用了相同的请求和响应,所以如果期望添加移动支持来显著提升您的访问流量,那么只需对应用程序执行性能测试即可。借助此技术,可简单地插入静态文件(.html、.css 和 .js),以便让托管现有 Web 应用程序的同一个域为它们提供服务,重用应用程序已提供的现有服务。
通过将限制自己仅创建新的静态资产,您实际上仅为现有的 Web 应用程序编写了一个客户端。
Web 应用程序:简史
大多数非平凡的 Web 应用程序都是围绕 模型 - 视图 - 控制器(MVC) 的概念构建的,其中控制器位于服务器上。服务器维护会话状态,通过转发或重定向,将用户请求导航到下一个要呈现的页面。每个客户端请求通常会得到整个页面的标记,即使在不同视图中仅更改了该页面的一部分。随后引入了 portlet 框架来解决这个问题,该框架支持更灵活地执行页面聚合。
然后,Ajax 开始迅速普及,而 Web 2.0也诞生了。Ajax 支持以编程方式发出异步请求。有效负载不再需要是标记,而是 XML,以及后来的 JSON。这使得控制器能够从服务器转移到客户端,页面聚合工作可卸载到越来越强大且更加标准化的客户端浏览器上。在一个极端上,Web 应用程序的浏览器和标记呈现器并无区别,所有功能和流由服务器管理。在该范围的另一个极端,Web 应用程序的许多控制和流逻辑在客户端浏览器上执行(像 JavaScript、Flash 或 Silverlight 一样),服务器提供 RESTful 服务来满足数据需求,并执行应用程序可能需要的任何繁重的计算。
提到移动 Web 应用程序,人们通常想到的是后一种模式,因为这是 jQuery Mobile 或 Dojo Mobile 等移动框架的设计方式。但是,在您需要让支持移动的应用程序拥有更加以服务器为中心的设计,而没有 REST 服务时,会发生什么?
将 Web 应用程序用作黑盒
因为我们的意图是避免对应用程序执行任何代码更改,所以可将应用程序视作一个黑盒,仅关注您获得的针对任何给定输入的输出;这里的输入指的是 HTTP 请求,输出指的是 HTTP 响应。因此,如果创建一个移动客户端来模拟特定的 HTTP 请求,并能够分析和识别该请求的所有可能响应,那么可以提供一种移动 “皮肤” 来利用现有应用程序的相同的请求 / 响应模式。尽管这在理论上听起来很简单,但实际上可能没那么简单。
登录序列
我们看看一个典型 Web 应用程序的身份验证序列的示例。(HTTP 请求和响应的详细信息可使用一个工具来收集,比如 Firefox Firebug 或者 Chrome 或 Safari 中的 Developer Tools。)我们首先看看来自提交凭据的位置的身份验证。清单 1 显示了登录表单的源代码标记。
清单 1
<form name="logonForm" action="/abc/salesportal/j_security_check" method="post"> <input type="hidden" name="page" value="signin.wss" /> <table cellspacing="0" cellpadding="0" class="sign-in-table"> <tr> <td class="c1"><label for="user_id">Email ID:</label></td> <td><input dir="ltr" class="wpsEditField" size="30" value="" name="j_username"id="user_id" type="text" /> (e.g., joe@abc.com)</td> </tr> <tr> <td class="c1"><label for="passwd">Password:</label></td> <td><input dir="ltr" class="wpsEditField" size="30" id="passwd" name="j_password"type="password" /></td> </tr> <tr><td><input type="hidden" name="login-form-type"value="pwd" /></td> </tr> <tr> <td> </td> <td><p><a href="http://www.abc.com/password">Forgot your password? </a></p></td> </tr> </table> <table cellspacing="0" cellpadding="0" class="submit-table"> <tr> <td class="buttons" align="right"> <span class="button-blue"> <input type="submit" value="Submit" name="submitButton" /> </span> <span class="button-blue"> <input type="button" value="Cancel" name="cancelButton" onclick="cancelSignIn()" /> </span> </td> </tr> </table> </form>
在上面的代码中,用户输入用户 ID 和密码并单击 Submit 时,可以看到凭据将传送到 j_security_check。非常简单。让我们模拟一个身份验证请求。
一个非常有用的 Web 应用程序黑盒测试工具是 cURL,它支持构建和跟踪 HTTP 交互。它为您提供了完整的控制权,支持您构建请求的每个方面(清单 2)。而且您完全无需担心浏览器缓存的变化无常。