详解在不使用ssr的情况下解决Vue单页面SEO问题


Posted in Javascript onNovember 08, 2018

遇到的问题:

近来在写个人博客的时候遇到了大家可能都会遇到的问题

Vue单页面在SEO时显得很无力,尤其是百度不会抓取动态脚本

Vue-Router配合前后端分离无法让meta标签在蜘蛛抓取时动态填充

Vue单页面又是大势所趋,写起来也不止是一个爽,当然也可以选择多页面

但即使是多页面在面对文章和文档时候也不可能说给每篇文章生成个Vue页面

SSR当然能解决这个问题,但是仔细想想SSR不就跟以前的.php页面一样了么

都是预先拉取所有数据然后填充返回给浏览器,需要多消耗服务器资源,而且配置繁琐

当然预渲染也不能解决这个问题

那么问题来了,我只是想让百度抓取下我的动态文章,但是配置个繁琐的SSR并不是最好选择

我的解决办法:

既然只是想让百度抓取下我的动态文章,其实就是让蜘蛛抓取我的静态页面时候,html的meta标签是已经填充好的

那么就很简单了,我们只需要实现一个极其简单的阉割版的SSR不就好了么

PS:我百度了很久没有找到相关的文章,不知道是不是我百度的姿势不对?

具体思路:

因为我的服务器后端语言是php,service是nginx,所以我这里展示的所有后端代码都是基于php,大家当然可以选择nodejs或者其他的语言去实现,这里提供个简单的思路

上面说到我们要实现个阉割版SSR,其实就是在服务器有请求过来的时候在静态html的meta标签上填充好数据然后返回给请求端

这里的实现都是基于已经构建好的Vue单页面,所以请先构建好一个Vue单页面

先把构建好的dist下的index.html改造下

在顶部将变量拿取到,因为接口都是现成的,所以偷个懒直接调取接口

<?php

$valDescription = '前端入门,进阶总结记录,个人日志博客,分享web学习经验的小窝。';
$valKeywords = 'web窝,前端,vue,js,博客,JavaScript,css,入门,教程';
$valTitle = 'web窝';

/**
 * 发送HTTP请求方法
 * @param string $url  请求URL
 * @param array $params 请求参数
 * @param string $method 请求方法GET/POST
 * @return array $data  响应数据
 */
function http_Req($url, $params, $method = 'GET', $header = array("Content-type: text/html; charset=utf-8"), $multi = false){
  if($method == 'POST'){
    $header = ["Content-type: application/x-www-form-urlencoded"];
  }
  $opts = array(
    CURLOPT_TIMEOUT    => 30,
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_HTTPHEADER   => $header
  );
  /* 根据请求类型设置特定参数 */
  switch(strtoupper($method)){
    case 'GET':
      $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
      break;
    case 'POST':
      //判断是否传输文件
      $params = $multi ? $params : http_build_query($params);
      $opts[CURLOPT_URL] = $url;
      $opts[CURLOPT_POST] = 1;
      $opts[CURLOPT_POSTFIELDS] = $params;
      break;
    default:
      throw new Exception('不支持的请求方式!');
  }
  /* 初始化并执行curl请求 */
  $ch = curl_init();
  curl_setopt_array($ch, $opts);
  $data = curl_exec($ch);
  $error = curl_error($ch);
  curl_close($ch);
  if($error) throw new Exception('请求发生错误:' . $error);
  return $data;
}
//分割当前请求的路径
$urlExp = explode('/',$_SERVER['REQUEST_URI']);
//如果当前的路径是文章内容
if(count($urlExp)>2 && $urlExp[1] == 'article'){
//请求当前文章的标题和描述
  $ret = json_decode(http_Req('http://127.0.0.1/api/Blog/getsinglelist',['tuid'=>$urlExp[2]],'POST'),true);
  $valKeywords = $ret['info'][0]['tt'].','.$valKeywords;
  $valDescription = $ret['info'][0]['txt'].' - '.$valTitle.','.$valDescription;
  $valTitle = $ret['info'][0]['tt'].' - '.$valTitle;
}
?>

将拿到的数据输出到meta标签上

<meta name="description" content="<?php echo $valDescription; ?>"/>
<meta name="keywords" content="<?php echo $valKeywords; ?>"/>

 
<title><?php echo $valTitle; ?></title>

然后把文件名改为index.php

写的很糙,反正就只有这一个功能,先扔到这

我的service是nginx,Vue-Router是history模式,所以当有html请求过来的时候我把所有原先转向index.html的请求都转向到了index.php

这样就实现了个阉割版的SSR

效果就像这样 web窝

每篇文章刷新的时候相应的meta标签都会提前填充好数据

配合nginx实现Vue-Router的history模式

当然只有history模式才有SEO的意义

只需要将nginx配置里原先转向index.html的地方改为index.php即可,Apache同理

location / {
  index index.php;
  alias /var/www/html/blog/;
  try_files $uri $uri/ /index.php;
}

关于后端接口请求的问题

因为我自己就一台服务器,后端语言是php

php所用的框架也需要伪静态

所以我的解决方式是用nginx配置根据二级域名,去代理所访问的路径

类似静态资源访问的都是cdn的二级域名,接口的请求访问的都是api的二级域名

server {
  listen    80;
  listen   443 ssl;
  server_name cdn.linkvall.cn;
  root     /var/blog;
}
server {
  listen    80;
  listen   443 ssl;
  server_name api.linkvall.cn;
  root     /var/api;
}

当然你可以简单的用请求的路径去配置

server {
  listen    80;
  listen   443 ssl;
  server_name cdn.linkvall.cn;
  root     /var;

 
location ~ ^/api/ {
alias /var/api;
}

 
location ~ ^/blog/ {
alias /var/blog/;
}
}

这样就可以把各自的资源路径区分开

写在最后

本来是打算用nodejs实现的,写一个npm包,跑一个node进程,然后nginx把请求反向代理到node端口,这样看上去更优雅

不过转念一想我的后端是php,直接代理到这个php文件可以省去写npm包的时间,就是构建好的html还要每次都更改下有一点点费劲,而且不优雅

这里更多的是提供一个思路,后面有时间了或许我会写一个npm包优雅的实现它

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript中使用正则匹配多条,且获取每条中的分组数据
Nov 30 Javascript
Js实现滚动变色的文字效果
Jun 16 Javascript
js实现ArrayList功能附实例代码
Oct 29 Javascript
使用Raygun对Node.js应用进行错误处理的方法
Jun 23 Javascript
javascript同步服务器时间和同步倒计时小技巧
Sep 24 Javascript
JavaScript中三种异步上传文件方式
Mar 06 Javascript
手机端图片缩放旋转全屏查看PhotoSwipe.js插件实现
Aug 25 Javascript
关于Vue.js一些问题和思考学习笔记(1)
Dec 02 Javascript
JavaScript和JQuery获取DIV值的方法示例
Mar 07 Javascript
canvas实现爱心和彩虹雨效果
Mar 09 Javascript
JS实现table表格固定表头且表头随横向滚动而滚动
Oct 26 Javascript
Weex开发之地图篇的具体使用
Oct 16 Javascript
Vux+Axios拦截器增加loading的问题及实现方法
Nov 08 #Javascript
Angular设置别名alias的方法
Nov 08 #Javascript
vue-cli安装使用流程步骤详解
Nov 08 #Javascript
vue项目动态设置页面title及是否缓存页面的问题
Nov 08 #Javascript
vue-awesome-swiper 基于vue实现h5滑动翻页效果【推荐】
Nov 08 #Javascript
Vue实现简易翻页效果源码分享
Nov 08 #Javascript
vue-cli3.0 环境变量与模式配置方法
Nov 08 #Javascript
You might like
《魔兽争霸3》重制版究竟重制了什么?玩家:这么糊弄真的好吗?
2020/05/04 魔兽争霸
不用数据库的多用户文件自由上传投票系统(2)
2006/10/09 PHP
PHP 面向对象 final类与final方法
2010/05/05 PHP
php 删除记录同时删除图片文件的实现代码
2010/05/12 PHP
在php和MySql中计算时间差的方法
2011/04/22 PHP
php curl模拟post请求小实例
2013/11/13 PHP
编写PHP程序检查字符串中的中文字符个数的实例分享
2016/03/17 PHP
PHP实现简单ajax Loading加载功能示例
2016/12/28 PHP
JavaScript 构造函数 面相对象学习必备知识
2010/06/09 Javascript
THREE.JS入门教程(4)创建粒子系统
2013/01/24 Javascript
javascript仿php的print_r函数输出json数据
2013/09/13 Javascript
js字符串日期yyyy-MM-dd转化为date示例代码
2014/03/06 Javascript
node.js入门教程迷你书、node.js入门web应用开发完全示例
2014/04/06 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
2015/08/13 Javascript
JavaScript中对JSON对象的基本操作示例
2016/05/21 Javascript
jquery轮播的实现方式 附完整实例
2016/07/28 Javascript
AngularJS基础 ng-hide 指令用法及示例代码
2016/08/01 Javascript
JS正则表达式学习之贪婪和非贪婪模式实例总结
2016/12/26 Javascript
基于JavaScript实现自定义滚动条
2017/01/25 Javascript
vue双向绑定简要分析
2017/03/23 Javascript
jQuery序列化后的表单值转换成Json
2017/06/16 jQuery
Angular6 Filter实现页面搜索的示例代码
2018/12/02 Javascript
ES6的解构赋值实例详解
2019/05/06 Javascript
Node Express用法详解【安装、使用、路由、中间件、模板引擎等】
2020/05/13 Javascript
Python中的is和==比较两个对象的两种方法
2017/09/06 Python
django定期执行任务(实例讲解)
2017/11/03 Python
python环形单链表的约瑟夫问题详解
2018/09/27 Python
Python设计模式之观察者模式原理与用法详解
2019/01/16 Python
基于Python的PIL库学习详解
2019/05/10 Python
使用python快速在局域网内搭建http传输文件服务的方法
2019/11/14 Python
this关键字的含义
2015/04/08 面试题
五分钟演讲稿
2014/04/30 职场文书
餐饮服务员岗位职责
2015/02/09 职场文书
初中政治教学工作总结
2015/08/13 职场文书
浅谈redis的过期时间设置和过期删除机制
2022/03/18 MySQL
centos7安装mysql5.7经验记录
2022/05/02 Servers