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

Client Side HTML MVC Rendering vs Server Side Rending via NodeJS

本文关键字:NodeJS 服务器端 MVC HTML 客户端      更新时间:2023-09-26

我们正在团队中寻找选项,以在基于Angular的客户端MVC方法和服务器端NodeJS/ExpressJS服务器端渲染方法之间做出选择。

我们的Angular应用程序下载为一个index.html,并发出XHR请求来填充页面。由于我们需要预先呈现页面,因此当内容更改到服务器上的某个位置时,我们使用PhantomJS来保存每个页面的副本。这允许支持SEO。

有没有完整页面主干应用程序或角度应用程序的例子,人们可以向我们指出,看看其他人是否在这样做。

或者是我们可以在野外看到的NodeJS服务器端渲染应用程序的例子。

最后,有人对这种建筑有意见吗?

我主要从事服务器渲染和客户端渲染应用程序。每种类型都有自己的优点和缺点。然而,你必须在两者之间做出选择的想法是错误的二分法。如果你有资源,你可以把两者结合起来,两全其美。

我看到纯客户端框架的4个主要挑战:

  • SEO和分析
  • 缓存
  • 内存
  • 延迟

SEO

因为你使用的是Node.JS,所以SEO问题可以通过简单地使用服务器上的客户端框架来为谷歌机器人和公司输出静态页面来缓解。最近,谷歌为单页应用程序制作了一个很好的分析API,但这将比简单地在主模板的末尾添加几行更多的工作。

缓存

缓存是加速任何web应用程序的一种非常重要的方式。对于少量数据,将客户端上的数据缓存到内存或localStorage中可能会更快,但上的存储空间非常有限(目前约为5MB)。另外,缓存失效在localStorage中很难做到。

内存

记忆是我为忽视而付出沉重代价的东西。在我意识到这一点之前,我意外地制作了一个占用超过200MB RAM的应用程序。我可能可以通过优化将其减少一半,但我怀疑如果我在服务器上渲染所有内容,它会占用超过20MB的空间。

延迟

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

37 Signals最近在博客中介绍了他们为新版Basecamp实现的混合客户端/服务器架构。这种混合方法使用服务器来呈现HTML,但利用客户端上的PJAX之类的东西来消除整个页面的刷新。效果真的很快,这是我推荐的。

在服务器上使用node.js,原则上您可以在客户端和服务器上使用相同的代码进行渲染。实现这种方法的框架是Meteor和Derby,它们还可以在客户端和服务器之间透明地同步数据模型。尽管两者仍被认为处于阿尔法状态,但似乎已经运行得很好了。

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

  • 客户端呈现的缺点是初始页面加载需要很长时间,但一旦加载了所有资源,用户就可以在没有页面的情况下无缝导航网站。您可能希望尽量减少Ajax调用的数量和/或使用客户端缓存(例如,在Angular.js控制器中缓存数据)
  • 服务器端呈现提供了快速的初始页面加载,有利于SEO,但每次用户导航时,在加载新URL时,整个页面都会在一秒钟内变为空白

因此,这一切都取决于你是想要快速的初始页面加载,但不希望用户停留那么长时间(然后使用服务器端渲染),还是页面快速加载并不重要(就像在Gmail中一样),但用户会在很长一段时间内导航(然后使用客户端渲染)。

我们目前正在测试这个疯狂的方法:我们有angularJS应用程序,它在客户端上运行。当我们检测到Googlebot作为代理时,我们运行PhantomJS实例,并用该实例的输出响应爬网程序。棘手的部分是知道你的客户端应用程序何时完成加载,这样你就可以选择并返回它。如果你想在客户端JS应用程序加载之前尽快完成,爬网程序就不会得到太多数据,主要是index.html。

简单的实现可以在这里找到:http://pastebin.com/N3w2iyr8

更新:在我写原始答案的时候,还不存在像prerendr.io这样的东西,但我现在可以向你指出。

我的解决方案是让谷歌可以在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脚本,并在终端中运行:nodesnapshot.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. 确保所有东西都能卷曲,输入终端

    卷曲http://aisel.dev/''_escaped_fragment_''=/page/关于aisel/这应该显示快照的内容/www/aisel.dev/public/web/snapshots/views/page/about aisel/index.html

不要为谷歌和其他爬虫指令。你的应用程序应该在头部包含元规则:

    <meta name="fragment" content="!">

谷歌的完整条款如下:https://developers.google.com/webmasters/ajax-crawling/docs/specification