客户端HTML MVC渲染与通过NodeJS进行服务器端渲染

21

我们正在寻找一个团队选项,决定采用基于 Angular 的客户端 MVC 方法还是服务器端 NodeJS / ExpressJS 服务器端渲染方法。

我们的 Angular 应用程序作为一个 index.html 下载,并通过 XHR 请求填充页面。由于需要预渲染页面,因此我们使用 PhantomJS 在服务器上的位置保存每个页面的副本,当内容更改时。这支持 SEO。

有没有完整页面的 backbone 应用程序或其他人可以指向的 Angular 应用程序的示例,以便我们查看其他人是否在使用这种方法。

另外,我们可以看到一些 NodeJS 服务器端呈现应用程序的示例吗?

最后,有没有人对这种架构有意见?


1
你能再解释一下,当内容更改到服务器上的位置时,保存页面是什么意思吗?你如何允许用户链接到Web应用程序的特定“页面”?或者这不适用吗? - dqhendricks
这是一个网站还是网络应用程序? - Tyson Nero
你好,我建议阅读这篇非常信息丰富的博客文章,介绍了目前市面上的MVC框架。虽然没有涉及Express,但它提供了很多思考的素材,可以帮助你在构建MVC应用程序之前选择适合的方法。链接:http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/。 - Sachin
4个回答

34

我曾经参与过大部分是服务器渲染和大部分是客户端渲染的应用程序开发。每种类型都有其优缺点。然而,认为你必须在两者之间选择一个是一种错误的二元对立观念。如果你有足够的资源,你可以将两者结合起来,以获得最佳效果。

我认为纯客户端框架存在四个主要挑战:

  • 搜索引擎优化和分析
  • 缓存
  • 内存
  • 延迟

搜索引擎优化

由于你正在使用Node.JS,可以通过在服务器上使用客户端框架来输出静态页面以供Googlebot等搜索引擎爬取,从而缓解SEO问题。最近,Google为单页应用程序提供了一个不错的Analytics API,但这需要比简单地在主模板末尾添加几行代码更多的工作。

缓存

缓存是加速任何Web应用程序的重要方法。对于少量数据,将数据缓存在客户端内存或localStorage中可能更快,但存储空间非常有限(目前约为5MB)。此外,在localStorage中进行缓存失效处理相当困难。

内存

内存是我曾经忽视的代价高昂的问题。在我意识到之前,我不小心制作了一个占用超过200MB内存的应用程序。通过优化,我可能能将其减少一半,但如果我全部在服务器上渲染,它可能不会占用超过20MB。

延迟

延迟也容易被忽视。例如,Drupal每个页面大约运行50到100个SQL查询。当数据库服务器紧挨着应用服务器时,您不必担心延迟,所有这些查询可以在几百毫秒内执行。您的客户端应用程序通常需要100毫秒才能发出单个AJAX请求。这意味着您需要花费大量时间设计服务器端API以最小化这些往返,但此时服务器已经拥有生成HTML所需的所有数据。如果您不小心的话,使用与正确RESTful接口交互的客户端应用程序可能会变得极其缓慢。

37 Signals最近在博客中提到了他们为Basecamp新版本实施的混合客户端/服务器架构。这种混合方法使用服务器来呈现HTML,但利用类似PJAX的东西在客户端上消除全页面刷新。效果非常快,是我推荐的做法。


8

使用 node.js 作为服务器,原则上您可以使用相同的代码在客户端和服务器上进行渲染。实现此方法的框架有 MeteorDerby,它们还可以在客户端和服务器之间透明地同步数据模型。但两者目前仍被视为测试版,但似乎已经运行得相当不错。

同时,客户端和服务器端渲染都有优缺点:

  • 客户端渲染的缺点是初始页面加载需要很长时间,但一旦所有资源加载完成,用户可以无缝地浏览网站而无需重新加载页面。您可能希望最小化 Ajax 调用的数量和/或使用客户端缓存(例如,在 Angular.js 控制器中缓存数据)。
  • 服务器端渲染提供快速的初始页面加载并且对于 SEO 很好,但每次用户导航时,整个页面会在加载新 URL 时变空白一秒钟。

因此,这完全取决于您是否希望快速加载初始页面,但不希望用户停留太久(然后使用服务器端渲染),或者页面加载速度不那么重要(如 Gmail)但用户将长时间浏览网页(然后使用客户端渲染)。


5
我们目前正在测试这种疯狂的方法: 我们有一个在客户端运行的AngularJS应用程序。当我们检测到Googlebot作为代理时,我们运行PhantomJS实例,并使用其输出响应爬虫。棘手的部分是知道何时客户端应用程序完成加载,以便您可以选择并返回它。如果您比客户端JS应用程序更早地执行此操作,爬虫将不会获得太多数据,主要是index.html。 简单的实现可以在这里找到: http://pastebin.com/N3w2iyr8 更新:在我撰写原始答案时,没有像prerendr.io这样的东西,但我现在可以指引您去查看

1
我想这是处理网络爬虫的最佳方法,而不是搞乱整个开发过程。 - Mahes

0
我的解决方案是让Angular应用程序可以被谷歌爬取。已在aisel.co中使用。
  1. 快照由https://github.com/localnerve/html-snapshots处理
  2. 在你的 .htaccess 文件中添加规则

    RewriteCond %{QUERY_STRING} ^_escaped_fragment_=(.*)$
    RewriteCond %{REQUEST_URI} !^/snapshots/views/ [NC]
    RewriteRule ^(.*)/?$ /snapshots/views/%1 [L]
    
  3. 创建用于快照的 node.js 脚本,并在终端中运行:node snapshots.js

    var htmlSnapshots = require('html-snapshots');
        var result = htmlSnapshots.run({
        input: "array",
        source: [
                "http://aisel.dev/#!/",
                "http://aisel.dev/#!/contact/",
                "http://aisel.dev/#!/page/about-aisel"
        ],
        outputDir: "web/snapshots",
        outputDirClean: true,
        selector: ".navbar-header",
        timeout: 10000
    }, function(err, snapshotsCompleted) {
        var fs = require('fs');
        fs.rename('web/snapshots/#!', 'web/snapshots/views', function(err) {
            if ( err ) console.log('ERROR: ' + err);
        });
    });
    
  4. 确保一切都能正常工作,使用 curl 命令,在终端中输入:

    curl http://aisel.dev/\?_escaped_fragment_\=/page/about-aisel/ 这应该显示快照的内容:.../www/aisel.dev/public/web/snapshots/views/page/about-aisel/index.html

不要担心谷歌和其他网络爬虫使用的指令。你的应用程序应该在头部包含meta规则:
    <meta name="fragment" content="!">

这里是来自谷歌的完整条款:https://developers.google.com/webmasters/ajax-crawling/docs/specification


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接