代码改变世界

服务器端逻辑还是客户端逻辑?

2009-10-05 13:23  Tower Joo  阅读(3653)  评论(8编辑  收藏  举报

服务器端逻辑还是客户端逻辑?

本博客所有内容采用 Creative Commons Licenses 许可使用. 引用本内容时,请保留 朱涛出处 ,并且 非商业 .

点击 订阅 来订阅本博客.(推荐使用 google reader, 如果你的浏览器不支持直接订阅,请直接在 google reader 中手动添加).

你也可以选择 下载pdf 来阅读.

摘要

做过几个基于web的项目,无论是游戏,网站等, 在这个过程中也遇到了一些问题和疑惑,但是 通常在朋友或者google的帮助下,都能够顺利解决.但是一个问题却一直困惑着自己:

在实现同一个功能时, 我们应该选择服务器端逻辑还是客户端的逻辑?

本文就此问题展开一些讨论. 同时,本文相关的讨论也可见 SOCPyUGTopLanguage.

欢迎大家一起来讨论.

问题引入

下面是我发自 CPyUG 和 TopLanguage 上的问题, 想看英文版的可点击 SO.

在做过几个基于web的项目后, 碰到了一个比较难把握的问题: 在实现同一个功能时, 我们应该选择服务器端逻辑还是客户端的逻辑?
举个简单的例子:
功能: 我现在想动态地显示一个页面
方案1: 服务器端的逻辑: 从数据库里取出数据使用服务器端代码(PHP,python)来生成格式化后的页面,返回给客户端,
然后客户端直接显示.(所谓的more server side logic, less client side logic)
方案2: 客户端的逻辑: 从数据库里直接取出数据, 并不格式化,而是以json或者xml返回给客户端,
让客户端的代码(javascript)来格式化,继而显示(所谓的more client side logic, less server side logic)
当然上面只是一个简单的例子, 可以推广到各种ajax的动态请求场景.
从用户的角度来看,二者的结果是一致的,但是程序员在处理时却是截然不同的. 所以出现了下面的几个问题:
我们应该优先选择哪种?
哪种有更好的performance?
哪种更user-friendly?

回答的总结

目前 SO 有8个左右的回复, 我简单总结如下.

支持服务器端逻辑:

  1. 安全性
  2. 搜索引擎友好
  3. 有更好的accessibility
  4. 更好的适应性(无论用户使用的是支持js或者不支持的)
  5. 用户体验的稳定性(由于不知道用户使用的是什么浏览器,也就不能确定js引擎的解析速度,所以可能某些浏览器用户会觉得很友好, 而某些会觉得很慢,而使用服务器端则取决于网络)
  6. 硬件成本的降低(这也是可预期的)

支持客户端逻辑:

  1. 用户友好(不需要refresh,而且通常会有更好的异步处理,所谓的ajax)
  2. 节省带宽,减少成本(当然传输pure data的json肯定会比格式化好的html节省更多的带宽)
  3. 扩展性(这点可能比较有争议,但是保持服务器端逻辑的简洁对于扩展性还是很有帮助的)
  4. 现代浏览器的发展(IE,FF, chrome相继宣称自己有更快的js引擎,所以js的解析速度会有大幅度的提升,而且使用老浏览器的用户也是极少的)

具体的分析

那我们不妨简单分析下这些答案.

安全性

永远不要相信用户的输入, 这是web开发的一个重要原则.为什么呢?因为客户端的输入我们是没法控制的, 恶意的用户会尝试 XSSsql injection 等, 甚至你的用户根本就不是人,而是一个机器人(模板浏览器行为).

举个例子,面对一个表单, 80%的用户会按照我们的预期填写相关的信息, 这时我们只需要客户端加入一些验证即可, 如(email验证, 表项是否为空验证等), 但是倘若用户使用的是恶意的机器人,这些验证都会失效,用户完全可以 绕开这些验证而直接提交给服务器. 这时便有了 安全性 问题. 所以更好的办法是, 除了客户端的验证外,我们 还需要服务器端的验证

当然,这只是一个简单的示例, 可以推广到更宽更广, 但是有一个原则是:

只要状态发生更改, 都需要服务器端的验证.

这里所谓的 状态发生更改, 可以理解为数据库的读写操作, 用户状态的更改等.

用户体验

用户体验是个很重要的问题, 随着 ajax 等技术的出现, 无刷新的类似于桌面应用的体验越来越受到用户的认可, 所以在我们的实际项目中,必须要考虑用户的体验.

针对于本文的主题, 这里就有2个方面的内容:

  1. 服务器端的因素
  2. 客户端的因素

服务器端,我们应该减少request,减少数据量, 节省带宽, 从而提高响应的速度. 那么从这个角度来看, 我们就应该减少服务器端的处理逻辑,而使用pure data来返回给用户.

客户端, 我们应该提高客户端代码的执行速度(javascript, css的解析), 那么相应的从这个角度来看, 我们就应该减少客户端的处理逻辑,而使得浏览器的引擎有更好的解析速度.

显然二者是一个矛盾!

但是可以考量的是, 随着硬件成本的降低和性能的提升, 服务器端的性能会相应的提升(增加服务器数量等), 同样,随着各大主流浏览器厂商的浏览器引擎性能的提升, 客户端的解析速度同样会大幅提升(IE, FF, chrome不是 相继声称自己的解析引擎是最快的吗?)

那么,我们就无法从用户体验的角度来得到一个统一的答案.

适用性和可用性

这个世界对于程序员来讲并不完美, 客户端并不是单一的一种, 浏览器也不是单一的一种,所以程序员得考虑 适用性和可用性.

大致可以将用户分为如下几类:

  1. 现代的浏览器(有完整的javascript/css支持)
  2. 老式的浏览器(无或者对javascript/css没有很好的支持,或者禁用了javascript的现代浏览器)
  3. 搜索引擎的机器人(如google的bot等)
  4. 移动终端(较小的显示设备,不完整的javascript/css支持)
  5. 特殊人群(如一些残障人士等)

从大的方面来看,也就是是否对javascript/css有良好的支持两类.

有很好支持的客户端: 那么我们如果用大量的客户端代码,则在用户体验等方面会有比较大的提高, ajax,无刷新,drag and drop等桌面应用的体验也会让用户倍觉舒心.

但是,另一类,如果客户端没有很好的支持: 那么对于无刷新的动态生成的内容,搜索引擎无法索引, 没有javascript/css很好支持的用户则无法使用相应的功能,那么可用性就大打折扣!

如何平衡?

我觉得还是得看应用的场景,如果是类似于游戏的这种频繁触发的应用, 就需要以用户的体验为中心, 使用ajax等技术来让用户得到更好的体验,宁可让那些没有javascript/css支持的用户不可用(我们 放弃这部分用户). 如果是基于内容的应用(如新浪的新闻,bbs等),则要强调可用,及尽少地依赖客户端的 机制,让各种客户端都能够很好地处理(手机,搜索引擎等).

成本

说起这个还有个比较有意思的事情, 记得研一时去IBM面试实习生, 与和蔼的面试官沟通时,谈到了硬件的成本 问题, 我当时自以为是地认为硬件成本已经很低了云云(2008年年初), 面试官和蔼地纠正了我, 并且以IBM 为实际的例子, 自此后,我便对于硬件的成本很敏感了.

回复正题, 既然硬件成本也是很关键的因素, 那么我们从这个角度来看下我们的主题.

减少服务器端的逻辑,减少传输的数据量, 毫无疑问可以减少带宽, 降低硬件开销(同等用户体验的前提下), 那么我们是否就应该更多依赖于客户端的逻辑?

其实归根结底是 成本和用户体验的平衡, 同等的硬件环境下, 更多地使用客户端逻辑,自然会导致相应的 解析时间增加, 用户体验下降. 同样,同等的用户体验下, 增加服务器数量和性能,势必会增加相应的硬件成本, 从而导致更多的开销.

但是一点是比较清楚的:

成本的控制是我们可控的, 而客户端的解析效率是我们无法控制的, 前者我们可以增加更多的服务器,提高服务器 的性能等,后者我们只能寄希望于用户有个好的,更快的浏览器. 所以,从这个角度来看, 如果你需要更多的掌控, 那前者不失为一种好办法 .

扩展性

扩展性,即 scalability , 参见 wikipedia 中的定义:

In telecommunications and software engineering, scalability is a desirable property of a system, a network, or a process,
which indicates its ability to either handle growing amounts of work in a graceful manner or to be readily enlarged.

也就是说,系统能够很优美地处理不断增长的需求.

那么, 我们可以假设, 我们的应用很受欢迎, 一周内PV不断增加, 这时,我们看看采用服务器端逻辑和客户端逻辑各自的结果.

  1. 服务器端逻辑: 随着用户数量的增加, 数据量急剧增加(因为单个请求的数据量比较大),如果要保持一定的用户体验,就必须增加硬件的投资
  2. 客户端逻辑: 随着用户数量的增加, 数据量一定的增加(因为单个请求的数据库量较小),而客户端的代码的执行速度并不下降,这时只需要添加少量的 硬件设备即可.

我们量化地描述下, 记纯数据(json)的数据量为: T, 服务器端处理时增加的数据量为 A, 网速 S, 客户端代码量 C, 客户端解析引擎处理速度 K,请求数N

我们假定用下面的数据来表示服务器端的相关信息:

T, A1, S, C1, K, N

那么,对应的响应时间为: total1 = ((T+A1)/S+C1/K)*N

相应地,我们假定用下面的数据来表示客户端的相关信息:

T, A2, S, C2, K, N

那么,对应的响应时间为: total2 = ((T+A2)/S+C2/K)*N = (T/S+C2/K)*N

那么U = total1-total2 = (A1/S+(C1-C2)/K)*N, 这里C2通常会是C1的数倍, 而A1/S服务器端处理逻辑所增加的响应时间,通常会是客户端逻辑所增加的处理 时间的若干倍, 而随着N的增加,U会急剧增加,在不增加服务器的前提下, 相比较客户端的逻辑, 服务器端的逻辑的方案在响应速度和用户体验方面会差好多.

那么这样就比较清楚了, 客户端的逻辑会在这种情况下具有较大的优势(当然我们假定的是不涉及安全性和客户端支持等).

结论

从上面的分析来看,用一句话来总结就是:

我们要根据实际的应用场景来选择具体的方案.

那么怎样的应用场景, 适合不同的方案呢?

我个人的见解是除了下面几种情况外,我都会优先使用客户端的逻辑:

  1. 安全性(如一些验证, 也就是状态更改相关的)
  2. 特殊人群(可能某些人群具有特殊的属性,如果我们的服务是针对这些人的,可能就要好好权衡)

后记

上面提到的几个讨论的帖子仍旧处于活跃状态,请大家可以随时留意,也欢迎大家留言讨论.

谢谢.

本文的rst源码

本文的源码链接在 这里 .