如何在不刷新页面的情况下更改路线和内容? (机器人友好)

Posted

技术标签:

【中文标题】如何在不刷新页面的情况下更改路线和内容? (机器人友好)【英文标题】:How to change route and content without page refresh? (robot friendly) 【发布时间】:2016-09-27 11:25:52 【问题描述】:

我想知道是否可以更改显示的 url,并据此更改页面的内容并使 url 和页面的内容对机器人友好(这意味着机器人实际上可以索引它们)。

我已经尝试过使用 AJAX 动态加载数据并使用 angularjs 路由,但它们都不能被机器人索引。

pretty urlsquery strings 也不是我想要的,我正在寻找一种理论,它可以在着陆时呈现数据并改变路线和在没有页面刷新的情况下点击链接的内容,我不想写两次代码(一次在服务器端,一次在前端)。

这些是我已经尝试过的东西,任何帮助或解决方案的指导将不胜感激。

更新

适用于所有语言且无依赖性的无库解决方案/结构将是最准确的答案!

【问题讨论】:

您正在混合 2 个不同的概念...... SEO 和人类可用的路由。对于某些搜索引擎来说,两者都是相同的。 SEO 方法取决于搜索引擎支持的内容。谷歌已经声称支持 ajax 驱动的网站已经有一段时间了……我不确定其他搜索引擎的状态。强烈建议您阅读有关此主题的 google 网站管理员指南...以及其他搜索引擎 ***.com/questions/13499040/… 如果您认为有必要,还有多种方法可用于为您的页面提供非 ajax 表示形式 google 建议将 pretty urls 用于 ajax 驱动的 Web 应用程序,但我想知道是否还有其他方法。 @charlietfl @maksbd19 ***.com/a/23245379/2832571 这太棒了 【参考方案1】:

以下内容可以代表解决方案的起点。 在继续阅读之前,请记住以下关于我的回答的主要事项:

所有原版 javascript ajax 调用加载新内容 更改地址栏上的网址而不重新加载页面 在浏览器历史记录中注册 url 更改 seo 友好

但请注意,所有内容均以草稿代码的形式呈现,旨在解释解决方案,如果您想在生产环境中实施,则需要改进代码。

让我们从索引页面开始。

index.php

<!DOCTYPE html>
<html>
<head>
    <title>Sample page</title>
    <meta charset="UTF-8">
    <script type="text/javascript" src="ajax_loader.js"></script>
</head>
<body>

<h1>Some static content</h1>
<a href="?main_content=external_content.php">
    Link to load dynamic content
</a>
<div id="main_content">
    <!--
        Here is where your dynamic content will be loaded.

        You can have as many dynamic container as you like.

        In my basic example you can attach one link to a
        single container but you can implement a more
        complete solution to handle multiple containers
        at the same time
    -->

    <!-- Leave this empty for the moment... some php will follow -->
</div>
</body>
</html>

现在让我们看看 javascript 如何处理链接以使用 ajax 加载内容

ajax_loader.js

window.onload = function() 

        var load = function(e) 
            // prevent browser to load link
            event.preventDefault();

            // exit if target is undefined
            if(typeof(e.target) == 'undefined' ) return;

            // exit if clicked element is not a link
            if (e.target.tagName !== 'A') return;

            // get href from clicked element
            var href = e.target.getAttribute("href");

            // retrieve container and source
            var href_parts = href.split('=');
            var container = href_parts[0].substr(1);
            var source = href_parts[1];

            // instantiate a new request
            var request = new XMLHttpRequest();

            // bind a function to handle request status
            request.onreadystatechange = function() 
                if(request.readyState < 4) 
                    // handle preload
                    return;
                
                if(request.status !== 200) 
                    // handle error
                    return;
                
                if(request.readyState === 4) 
                    // handle successful request
                    successCallback();
                
            ;

            // open the request to the specified source
            request.open('GET', source, true);
            // execute the request
            request.send('');

            successCallback = function() 
                // on success place response content in the specified container
                document.getElementById(container).innerHTML = request.responseText;

                // change url in the address bar and save it in the history
                history.pushState('','',"?"+container+"="+source);
            
        ;

        // add an event listener to the entire document.
        document.addEventListener('click', load, false);
        // the reason why the event listener is attached
        // to the whole document and not only to the <a>
        // elements in the page is that otherwise the links
        // included in the dynamic content would not
        // liste to the click event

    ;

现在让我们回顾一下 html 的一些特定元素

如前所述,提议的脚本会将行为附加到任何链接,您只需对其进行格式化,以便 load() 函数正确读取。格式为“?container_name=filename.php”。其中container_name是要加载内容的div的id,而filename.php是ajax调用获取内容的文件名。

因此,如果您的“external_content.php”文件中有一些内容并希望将其加载到 id 为“main_content”的 div 中,这就是您要做的

<a href="?main_content=external_content.php">Your link</a>
<div id="main_content"></div>

在本例中,页面首次加载时 div 'main_content' 为空,点击链接时将填充 external_content.php 文件的内容。 同时您浏览器的地址栏将从 http://www.example.com/index.php 到 http://www.example.com/index.php?main_content=external_content.php 并且这个新的 url 将被注册到你的浏览器历史记录中

现在让我们更进一步,看看我们如何使这个 SEO 友好,以便 http://www.example.com/index.php?main_content=external_content.php 是一个真实的地址,当我们加载页面时,'main_content' div 不为空。

我们可以添加一些 php 代码来处理这个问题。 (请不要说您甚至可以为类似的工作编写一些 javascript,但是由于您提到了使用服务器端语言,我决定使用 php)

<a href="?main_content=external_content.php">Load</a>
<div id="main_content">
    <?php dynamicLoad('main_content','default_main_content.php'); ?>
</div>

在展示它之前,我想解释一下 php 函数 dynamicLoad() 的作用。它有两个参数,第一个相当于容器id,第二个是默认内容所在的文件。 更清楚地说,如果请求的 url 是 http://www.example.com/ 该函数会将 default_main_content.php 的内容放入 main_content div 但是如果浏览器请求的 url 是 http://www.example.com/index.php?main_content=external_content.php 然后函数会将 external_content.php 的内容放在 main_content div 中。

这种机制有助于页面对 SEO 和用户友好,所以当搜索引擎爬虫会跟随 href “?main_content=external_content.php” 这带来了网址 "http://www.example.com/index.php?main_content=external_content.php" 将找到与 ajax 调用动态显示的相同内容。 对于将通过刷新或从历史记录重新加载页面的用户来说也是如此。

这里是简单的dynamicLoad() php函数

<?php
    function dynamicLoad($contaner,$defaultSource)
        $loadSource = $defaultSource;
        if(isset($_GET[$contaner])) 
            $loadSource = $_GET[$contaner];
        
        include($loadSource);
    
?>

正如第一行所说,这不是准备好生产的代码,它只是对您提出的请求的可能解决方案的解释

更改显示的 url 并据此更改内容 页面并使页面的 url 和内容成为机器人 友好的

【讨论】:

非常感谢 Igor 的详细解释,您的答案与@Ardeshir 之前解释的几乎相同,所以我能想到的解决方案的唯一问题是(正如我对 Ardeshir 的回答所做的评论) ) 服务器的数据传输率会非常高!因为您必须从服务器获取渲染页面,所以想象一个包含 100 个搜索内容和 20,000 多个用户请求它的页面,我猜服务器会爆炸。但是由于您是唯一一个在纯 js 中提供解决方案并且还经历了一些细节的人,所以我会接受您的回答!再次感谢你 我不知道您是否已经为您的项目准备了一些东西,但请考虑像 Cloud 和 Amazon WS 这样的可靠基础架构可以提供比您预期更好的性能。根据应用程序的类型,您还应该考虑在 Php 与 Node.js、SQL 与 MondoDB 技术方面做出正确的选择,并且不要将您的研究局限于这些。 Solr 和 Spark 是用于数据驱动应用程序的两个有趣的 Apache 解决方案……这完全取决于您的需求。 另一方面也考虑到你可以区分来自搜索引擎爬虫和浏览器的流量并处理一些不同的请求,例如使用始终 ajax 来加载动态容器内的内容,即使是在第一次加载时,并为网络爬虫一次性加载内容,如果您真的觉得这会影响您的项目 “你可以区分来自搜索引擎爬虫和浏览器的流量”这正是我想要避免的!现在它已经出现了,我实际上创建了一个结构来处理我所要求的所有事情(还处理客户端的所有数据绑定,因此数据传输率达到最低)并且它不依赖于任何图书馆,我只是想看看是否有人在发布之前已经完成了它。您的回答与我的方法最接近,再次感谢您;)【参考方案2】:

我认为您的页面未正确编入索引的主要问题可能是由于网址中的#

对于 AngularJS 的 SEO,请查看以下链接,

https://www.deepcrawl.com/knowledge/best-practice/angular-js-and-seo/ https://scotch.io/tutorials/angularjs-seo-with-prerender-io https://weluse.de/blog/angularjs-seo-finally-a-piece-of-cake.html

【讨论】:

我的网址没有 # ,我想你的问题错了,我目前也没有使用 angularjs 是的,我试过了,让它工作了,但并没有达到预期的效果(性能和代码长度,更不用说增加的库大小) 我不明白。图书馆对于任何项目都是不可避免的。不建议一次又一次地重新发明***。有人已经为您做到了,那么为什么不直接使用它呢?能否请您说说您在使用 AngularJS 时遇到了哪些性能问题? 在某些情况下(大项目)你需要性能,所以你必须自己编写一些库和代码,这不是重新发明***,而是根据你的需要优化***!我们在这个项目中试图做的是性能第一,它必须尽可能轻量级,解释细节可能会让每个人感到厌烦,所以我们就说我们不能使用库【参考方案3】:

实际上有一种方法可以做到这一点。我使用 AngularJS,正如有人正确指出的那样,谷歌现在将毫无问题地索引您的网站(如果我没记错的话,那是去年 6 月)。 Facebook 和其他此类网站不抓取 JavaScript,因此您需要其他解决方案。

最简单的方法是使用prerender.io,因为它将使用_escaped_fragment_ 参数并生成您页面的HTML 快照。这些只会在页面被请求时生成。

除此之外,唯一真正的解决方案是使用PhantomJS 并自己创建快照。这并不像听起来那么困难。当您更改视图时,您可以使用 Gulp 或 Grunt 之类的工具生成快照。

希望对你有帮助。

【讨论】:

谢谢,但我实际上是在寻找没有库或工具帮助的解决方案【参考方案4】:

您可以通过 React 等工具使用服务器端渲染,并且在您的应用程序 (js) 中只需通过 history.pushState() 更改 URL。 对于您的第一个问题(更改 URL),请查看this example。对于您的第二个问题(编写一次代码),使用服务器端呈现方法将解决问题,因为它呈现需要的元素转换成 HTML 字符串,然后将其作为响应发送给客户端。

【讨论】:

但是如果将整个页面从服务器发送到客户端会不会很昂贵?恕我直言,数据传输率将飙升 我假设您正在谈论一个包含许多元素(如列表)的大页面,如果我们将接收一些原始数据并在客户端进行模板化,那么我们将获得更轻的数据传输。确实如此,但您需要一个对机器人友好的内容,并且在让机器人可读的内容和增加一点页面大小之间进行权衡。我的观点是你不需要写两次页面内容,例如一次在 Razor 中,一次在 JS 中。 我知道,但我认为我们必须跳出框框思考,尝试减少数据传输以拥有完美的包!您的答案是迄今为止最接近的,服务器流量只是一个小问题......如果我们不必使用库或工具来实现这个想法,那将是最好的,这是一个适用于所有语言的解决方案会是最好的。 您可以在纯 JavaScript 中实现此模式,而且您是对的,我们应该找到解决大负载问题的方法。【参考方案5】:

如果您真的关心您的 SEO,您不应该使用 AJAX 来动态填充您的网站,这与 Google 蜘蛛无关,因为它可以以简单的方式读取 JavaScript,而是适用于其他搜索引擎蜘蛛。

最好和最古老的方法是使用普通路由,但你可以用 nodeJS 模拟它们并做出反应,这样你就可以使用 Javascript 来填充你的内容,如果我有正确的话,这称为同构。

http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/

更新:

只能在客户端运行的应用程序无法将 HTML 提供给爬虫,因此默认情况下它的 SEO 会很差。网络爬虫通过向网络服务器发出请求并解释结果来发挥作用;但是如果服务器返回一个空白页面,它就没有多大价值了。有一些解决方法,但并非没有跳过一些障碍。 来源 Airbnb 网站

不同之处在于用户过期客户端渲染的速度和网络爬虫从服务器获取内容。

【讨论】:

动态调用和同构方式有滑动区别。我可以引用完整的网站,但最好仔细阅读。 @J.Overmars 感谢您提供的信息,我会看看您的链接,听起来不是一件简单的事情(这是一个缺点)+1 反正... 我知道您的问题没有简单的答案,而且实现起来并不难,因为您可以在服务器端使用相同的 javascript。 我会阅读您分享的文章并稍后与您进一步讨论,再次感谢 我读了这篇文章,有一个小问题,你必须使用一些库或工具,如 node.js(这很糟糕,因为它限制了你),一个简单的无库解决方案是我认为最好的方法

以上是关于如何在不刷新页面的情况下更改路线和内容? (机器人友好)的主要内容,如果未能解决你的问题,请参考以下文章

Django - 如何在不刷新页面的情况下保持在同一页面上?

有没有办法在不刷新页面的情况下更改浏览器的地址栏?

使用 ajax 在不刷新站点的情况下更改 mongoDB 中的某些项目

如何在不刷新php页面的情况下跟踪mysql数据库中的更改?

如何在不轮询的情况下监视页面的更改?

如何在不更改页面的情况下更改内容(非散列 URL)?