用于静态网页的AngularJS SEO(S3 CDN)

我一直在寻找各种方法来改善托管在CDN上的angularJS应用程序的搜索引擎优化(如Amazon S3)(即无后端的简单存储)。 大多数解决方案,PhantomJS,prerender.io,seo.js等都依赖后端来识别爬虫生成的?_escaped_fragment_ url,然后从别处获取相关页面。 即使提前生成快照页面,即使是grunt-html-snapshot最终也需要你这样做。

这个解决方案基本上依赖于使用cloudflare作为反向代理,这似乎有点浪费,因为他们的服务提供的大多数安全设备等对于静态站点来说是完全冗余的。 按照这里建议的方式自己设置反向代理似乎也存在问题,因为它需要或者i)路由所有AngularJS应用程序我需要静态html通过一个代理服务器,这可能会妨碍性能,或者ii)为每个应用程序设置单独的代理服务器在这一点上,我可能会建立一个后端,这在我工作的规模上是不可承受的。

有没有这样做,或者是静态托管AngularJS应用程序与伟大的SEO基本上是不可能的,直到谷歌更新他们的抓取工具?


按照John Conde的评论转发给网站管理员。


这里是一个完整的概述如何使你的应用程序搜索引擎友好的存储服务,如S3,与漂亮的网址(无#)和一切与咕噜与构建后执行简单的命令:

grunt seo

这仍然是一个解决方法的难题,但它的工作原理是最好的。 感谢@ericluwj和他的博客文章,激励着我。

概观

目标和网址结构

目标是在角度应用程序中为每个状态创建1个html文件。 唯一主要的假设是你通过使用html5history(你应该这么做!)从你的url中删除'#',并且你的所有路径都是绝对路径或者使用角度状态。 有很多文章解释如何这样做。

网址以像http://yourdomain.com/page1/这样的尾部斜线结尾

就我个人而言,我确信http://yourdomain.com/page1(无尾随斜线)也可以到达目的地,但这不是题目。 我还确保每种语言都有不同的状态和不同的网址。

SEO逻辑

我们的目标是当有人通过http请求访问您的网站时:

  • 如果它是一个搜索引擎爬行器:让他在包含所需html的页面上。 该页面还包含角色逻辑(例如启动您的应用程序),但抓取工具无法读取,因此他故意卡住了您为他服务的html并将其编入索引。
  • 对于普通人和智能机器:确保角度被激活,擦除生成的html并正常启动您的应用程序
  • 咕噜的任务

    在这里,我们将与咕噜声一起完成任务:

      //grunt plugins you will need:
      grunt.loadNpmTasks('grunt-prerender');
      grunt.loadNpmTasks('grunt-replace');
      grunt.loadNpmTasks('grunt-wait');
      grunt.loadNpmTasks('grunt-aws-s3');
    
      //The grunt tasks in the right order
      grunt.registerTask('seo', 'First launch server, then prerender and replace', function (target) {
        grunt.task.run([
          'concurrent:seo' //Step 1: in parrallel launch server, then perform so-called seotasks
        ]);
      });
    
      grunt.registerTask('seotasks', [
        'http', //This is an API call to get all pages on my website. Skipping this step in this tutorial.
        'wait', // wait 1.5 sec to make sure that server is launched
        'prerender', //Step 2: create a snapshot of your website
        'replace', //Step 3: clean the mess
        'sitemap', //Create a sitemap of your production environment
        'aws_s3:dev' //Step 4: upload
      ]);
    

    步骤1:使用concurrent:seo启动本地服务器

    我们首先需要启动本地服务器(如grunt serve),以便我们可以拍摄我们网站的快照。

    //grunt config
    concurrent: {
      seo: [
        'connect:dist:keepalive', //Launching a server and keeping it alive
        'seotasks' //now that we have a running server we can launch the SEO tasks
      ]
    }
    

    第2步:使用grunt预渲染为您的网站创建快照

    grunt-prerender插件允许您使用PhantomJS拍摄任何网站的快照。 在我们的案例中,我们想要拍摄我们刚刚启动的localhost网站的所有页面的快照。

    //grunt config
    prerender: {
      options: {
        sitePath: 'http://localhost:9001', //points to the url of the server you just launched. You can also make it point to your production website.
        //As you can see the source urls allow for multiple languages provided you have different states for different languages (see note below for that)
        urls: ['/', '/projects/', '/portal/','/en/', '/projects/en/', '/portal/en/','/fr/', '/projects/fr/', '/portal/fr/'],//this var can be dynamically updated, which is done in my case in the callback of the http task
        hashed: true,
        dest: 'dist/SEO/',//where your static html files will be stored
        timeout:5000,
        interval:5000, //taking a snapshot of how the page looks like after 5 seconds.
        phantomScript:'basic',
        limit:7 //# pages processed simultaneously 
      }
    }
    

    第3步:用grunt替换清理混乱

    如果您打开预渲染的文件,它们将适用于抓取工具,但不适用于人类。 对于使用chrome的人来说,你的指令会加载两次。 因此,在角度激活之前(即,在头后),您需要将智能浏览器重定向到您的主页。

    //Add the script tag to redirect if we're not a search bot
    replace: {
      dist: {
        options: {
          patterns: [
            {
              match: '<head>',
              //redirect to a clean page if not a bot (to your index.html at the root basically).
              replacement: '<head><script>if(!/bot|googlebot|crawler|spider|robot|crawling/i.test(navigator.userAgent)) { document.location = "/#" + window.location.pathname; }</script>'
              //note: your hashbang (#) will still work.
            }
          ],
          usePrefix: false
        },
        files: [
          {expand: true, flatten: false, src: ['dist/SEO/*/**/*.html'], dest: ''} 
        ]
      }
    

    还要确保在你的ui-view元素的index.html中有这样的代码,它清除了所有生成的html指令之前的角度启动。

    <div ui-view autoscroll="true" id="ui-view"></div>
    
    <!-- this script is needed to clear ui-view BEFORE angular starts to remove the static html that has been generated for search engines who cannot read angular -->
    <script> 
      if(!/bot|googlebot|crawler|spider|robot|crawling/i.test( navigator.userAgent)) { document.getElementById('ui-view').innerHTML = ""; }
    </script>
    

    第4步:上传到aws

    您首先上传包含您的构建的dist文件夹。 然后用覆盖和更新的文件覆盖它。

    aws_s3: {
      options: {
        accessKeyId: "<%= aws.accessKeyId %>", // Use the variables
        secretAccessKey: "<%= aws.secret %>", // You can also use env variables
        region: 'eu-west-1',
        uploadConcurrency: 5, // 5 simultaneous uploads
      },
      dev: {
        options: {
          bucket: 'xxxxxxxx'
        },
        files: [
          {expand: true, cwd: 'dist/', src: ['**'], exclude: 'SEO/**', dest: '', differential: true},
          {expand: true, cwd: 'dist/SEO/', src: ['**'], dest: '', differential: true},
        ]
      }
    }
    

    就是这样,你有你的解决方案! 人类和机器人都能够读取您的网络应用程序


    其实这是一个确实非常麻烦的任务,但是我已经成功地将SEO与我的AngularJS SPA站点(在AWS S3上托管)配合使用,网址为http://www.jobbies.co/。 主要想法是预先生成并将内容填充到HTML中。 当页面加载并且预渲染的内容将被替换时,模板仍将被加载。

    您可以在http://www.ericluwj.com/2015/11/17/seo-for-angularjs-on-s3.html上阅读有关我的解决方案的更多信息,但请注意,有许多条件。


    如果你以有趣的方式使用ng-cloak,可能会有一个很好的解决方案。

    我自己并没有尝试过,但它理论上应该起作用

    该解决方案高度依赖于CSS,但它应该很好。 例如,您在角度应用程序中有三个状态: - index(pathname:#/) - about(pathname:#/ about) - contact(pathname:#/ contact)

    索引的基本情况也可以添加,但会很棘手,所以我现在就把它保留下来。

    让你的HTML看起来像这样:

    <body>
        <div ng-app="myApp" ng-cloak>
            <!-- Your whole angular app goes here... -->
        </div>
        <div class="static">
            <div id="about class="static-other">
                <!-- Your whole about content here... -->
            </div>
            <div id="contact" class="static-other">
                <!-- Your whole contact content here... -->
            </div>
            <div id="index" class="static-main">
                <!-- Your whole index content here... -->
            </div>
        </div>
    </body>
    

    (重要的是,如果你想让它更加真棒,你可以将你的索引案例放在最后)

    Next让你的CSS看起来像这样: -

    [ng-cloak], .static { display: none; }
    [ng-cloak] ~ .static { display: block; }
    

    无论如何,这可能对你来说足够好。 当角度未加载时,mg-cloak指令将保持您的角度应用隐藏,并将显示您的静态内容。 Google会在HTML中获得您的静态内容。 作为奖励,最终用户还可以在角度加载时看到很好的样式静态内容。

    如果您开始在CSS中使用target伪选择器,那么您可以获得更多的创意。 您可以在静态内容中使用实际链接,但只需将它们链接到各种ID。 所以在#index div中确保你有#about和#contact的链接。 注意链接中缺少的'/'。 HTML ID不能以斜线开头。

    然后让你的CSS看起来像这样:

    [ng-cloak], .static { display: none; }
    [ng-cloak] ~ .static { display: block; }
    .static-other {display: none;}
    .static-other:target {display: block;}
    .static-other:target ~ .static-main {display: none;}
    

    您现在拥有一个全功能的静态应用程序WITH ROUTINg,可在角度启动之前工作。

    作为额外的好处,当角度启动时,它足够聪明,可以自动将#about转换为#/ about,并且体验甚至不会中断。

    另外,当然,不要忘记SEO问题已经完全解决了。 我还没有使用过这种技术,因为我一直有一台服务器可以配置,但我非常感兴趣的是如何解决这个问题。

    希望这可以帮助。

    链接地址: http://www.djcxy.com/p/89611.html

    上一篇: AngularJS SEO for static webpages (S3 CDN)

    下一篇: How to make a SPA SEO crawlable?