单页应用SPA做SEO的一种清奇的方案

单页应用SPA做SEO的一种清奇的方案

网上有好几种单页应用转seo的方案,有服务端渲染ssr、有预渲染prerender、google抓AJAX、静态化。。。这些方案都各有优劣,开发者可以根据不同的业务场景和环境决定用哪一种方案。本文将介绍另一种思路比较清奇的SEO方案,这个方案也是有优有劣,就看读者觉得适不适合了。

项目分析

我的项目是用react+ts+dva技术栈搭建的单页应用,目前在线上已经有几十个页面,若干个sdk和插件在里面。

  • 考虑想用服务端渲染来做seo,但是我的项目已经开发了这么多,打包配置、代码分割、语法兼容、摒弃浏览器对象,服务端思想,这么多的点需要考虑,还不如换个框架重新开发呢,所以改造成本太大??,服务端渲染不适合我这种情况。
  • 预渲染虽然是开发成本最低的,但毕竟是生成一张一张的静态html,而我的seo需求是能够让蜘蛛抓取到我的社区论坛下的每一篇帖子,这样子下来一篇帖子就是一份html,再加上分页,那得多大的量级来存储啊??,而且网站更新就更麻烦了,这个方案也不太适合。
  • google.....Emmmm.........................下一个
  • 静态化也是跟预渲染差不多。。。

隆重介绍

以前写过一种单页应用seo的方案,就是自己先在本地用爬虫做预渲染,生成同样目录结构的静态化的html,前端项目服务器判断请求的UA是搜索引擎蜘蛛的话就会转发到我事先静态化过的html页面

当时的项目只是一个简单的只有几个页面的企业官网,预渲染没啥问题。

跟着这个思路,只要判断搜索引擎蜘蛛让蜘蛛看到另一个有数据的页面不就行了。

至于页面长什么样,蜘蛛??才不会管呢,就像是你找广告商投放广告,广告商不会要求你要怎样的主题什么色调,只要你按照他的尺寸和要求来做,然后给钱给货就完事了??。

所以可以针对SEO做另一套网站,没有样式,只有符合seo规范的html标签和对应的数据,不需要在原有项目上改造,开发成本也不会很高,体积小加载速度更快。

缺点也有,就是需要另外维护一套网站,主网站界面变化不会影响,如果展示数据有变化就需要同步修改seo版的网站。

代码实现

先建个单独的seo文件夹,不需要动到原有项目,下面是代码结构:

代码实现非常之简单,只要写一个中间件拦截请求,鉴别蜘蛛,返回对应路径的seo页面即可。

我的前端服务器是用express,可以写个express的中间件, 新建server.js:

// seo/server.js
const routes = require(‘./routes‘)
const layout_render = require(‘./src/layout‘);

module.exports = (req, res, next) => {
  // 各大搜索引擎蜘蛛UA
  const spiderUA = /Baiduspider|bingbot|Googlebot|360spider|Sogou|Yahoo! Slurp/
  var isSpider = spiderUA.test(req.get(‘user-agent‘))
  // 获取路由表的路径
  var seoPath = Object.keys(routes)
  if (isSpider) {
    for (let i=0,route; route = seoPath[i]; i++) {
      if (new RegExp(route).test(req.path)) {
        routes[route](req).then((result) => {
          // 返回对应的模板结果给蜘蛛
          res.set({‘Content-Type‘: ‘text/html‘,‘charset‘: ‘utf-8mb4‘}).status(200).send(layout_render(result))
        })
        break;
      }
    }
  } else {
    // 未匹配到蜘蛛则继续后面的中间件
    return next()
  }
}

然后在前端的启动服务器里加入这个中间件,记得要放在其他中间件之前

// 前端启动服务器的server文件
var express = require(‘express‘)
var app = express()
// seo
app.use(require(‘seo/server‘));
......

app.listen(xxxx)

接下来就是写模板和对应的解析了, 新建一个home文件夹,文件夹下再建一个index.ejs和index.js

<!-- seo/src/home/index.ejs -->
<div>
  <h1>官网首页</h1>
  <p>友情链接:</p>
  <p><a href="https://www.baidu.com/" target="_blank">百度</a></p>
  <p><a href="https://www.gogole.com/" target="_blank">谷歌</a></p>
</div>

index.js用于解析对应的ejs模板

// seo/src/home/index.js
const ejs = require(‘ejs‘)
const fs = require(‘fs‘)
const path = require(‘path‘)
const template = fs.readFileSync(path.resolve(__dirname, ‘./index.ejs‘), ‘utf8‘);

// 这里为什么会有个async关键字,往后面看就可以知道。
module.exports = async (req) => {
  const result = ejs.render(template)
  return result
}

我们还可以建多个layout模板来管理head、title和导航栏这些公有的元素

<!-- seo/layout.ejs -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name=”renderer” content=”webkit”>
  <meta content="网站关键字"" name="keywords"/>
  <meta content="网站描述" name="description"/>
  <title>网站标题</title>
</head>
<body>
  <div id="root">
    <ul>
      <li><a href="/">首页</a></li>
      <li><a href="/community">社区</a></li>
    </ul>
    <%- children -%>
  </div>
</body>
</html>

解析layout.ejs,套入内容的layout_render:

// seo/layout.js
const ejs = require(‘ejs‘)
const fs = require(‘fs‘)
const path = require(‘path‘)
const template = fs.readFileSync(path.resolve(__dirname, ‘./layout.ejs‘), ‘utf8‘);

const layout_render = (children) => {
  return ejs.render(template, {children: children})
}
module.exports = layout_render

路由表用简单的键值对就可以了,键名用字符串形式的正则来表示路径的匹配规则:

// seo/routes.js
const home_route = require(‘./src/home/index‘)

module.exports = {
  ‘^(/?)$‘: home_route,
}

那么数据如何做请求并展示到对应的模板内呢?数据请求是异步的,怎样等到请求完成再渲染模板呢?

我们可以用async/await来实现,现在来做一个社区的帖子列表页面,需要先请求社区下帖子列表数据再把数据渲染到模板,新建一个community文件夹,同样再建一个index.ejs作为帖子列表页面模板:

<!-- seo/src/community/index.ejs -->
<div>
  <h1>帖子列表</h1>
  <ul>
    <% forum_list.map((item) => { %>
    <li><a href="/community/<%= item.id%>" target="_blank"><%= item.title-%></a></li>
    <% })%>
  </ul>
</div>

相关的接口请求及数据操作写在同级的index.js:

// seo/src/community/index.js
const ejs = require(‘ejs‘)
const fs = require(‘fs‘)
const path = require(‘path‘)
const template = fs.readFileSync(path.resolve(__dirname, ‘./index.ejs‘), ‘utf8‘);
const axios = require(‘axios‘);

module.exports = async (req) => {
  const res = await axios.get(‘http://xxx.xx/api/community/list‘)
  const result = ejs.render(template, {forum_list: res.data.list})
  return result
}

这样就实现了先取接口数据再做渲染,保证了蜘蛛访问能给到完整的数据和html结构。

继续实现一个帖子详情的页面:

<!-- seo/src/community_detail/index.ejs -->
<div>
  <h1><%= forum_data.title%></h1>
  <p><%= forum_data.content%></p>
  <p>作者:<%= forum_data.user.nickname%></p>
</div>
// seo/src/community_detail/index.js
const ejs = require(‘ejs‘)
const fs = require(‘fs‘)
const path = require(‘path‘)
const template = fs.readFileSync(path.resolve(__dirname, ‘./index.ejs‘), ‘utf8‘);
const axios = require(‘axios‘);

module.exports = async (req) => {
  const forum_id = req.path.split(‘/‘)[2]
  const res = await axios.get(`http://xxx.xx/api/community/${forum_id}/details?offset=1&limit=10`)
  const result = ejs.render(template, {forum_data: res.data})
  return result
}

这样就实现了一个简单的seo版网站,不需要任何样式,不需要js做弹框之类的后续交互,只要蜘蛛访问网址的第一个请求有它要的数据即可,是不是非常的清奇??。。。

总结来说呢,就是如果你的项目处在线上运营阶段并且开发到了一定的集成度了,迫于ssr的改造成本太大,又需要让一些数据(比如每一篇文章帖子)能够被收录,就可以考虑一下我的这个方法??。

但是我不保证蜘蛛的防作弊机制,会不会过滤掉我这种跟浏览器正常访问主站差异较大的seo版小网站??。目前这个方案还在试验阶段。

测试

测试也很简单,写个模拟蜘蛛请求即可,curl、爬虫、postman都可以模拟蜘蛛的UA来测试。或者改一下搜索引擎蜘蛛的的判断条件就可以直接用浏览器访问的呢。



如果有朋友用了我这个方法并且真的有用能够被搜索引擎收录的话,请记得我??,要是能打赏就更好了哈哈??。

原文地址:https://www.cnblogs.com/lipten/p/9609678.html

时间: 2024-08-27 22:47:50

单页应用SPA做SEO的一种清奇的方案的相关文章

单页应用 SPA(Sigle Page Aolication)

单页应用 SPA(Sigle Page Aolication) 优点: 1.具有桌面应用的即时性.网站的可移植性和可访问性. 2.用户体验好.快,内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷. 3.基于上面一点,SPA相对对服务器压力小. 4.良好的前后端分离.SPA和RESTful架构一起使用,后端不再负责模板渲染.输出页面工作,web前端和各种移动终端地位对等,后端API通用化. 缺点: 1.不利于SEO. 2.初次加载耗时相对增多. 3.导航不可用,如果一定要导航需要

单页应用SPA开发最佳实践

最近用vue+vue-router做了个单页应用的项目,页面大概有15个左右.积累了一些开发经验在此做一些记录.本文主要从可维护性方面来考虑SPA的开发实践 全站的颜色定义放在一个less或者scss的文件里,其他组件和页面import这个配置来引用颜色. 示例代码:define.scss $bgColor: #fff; $color:#619eee; $fontColor:#333333; $fontColor01:#A5A5A5; $fontColor02:#4a4a4a; $fontCol

React单页应用SPA

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React-SPA</title> <script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script> <script src=

Nodejs之MEAN栈开发(六)---- 用Angular创建单页应用

在上一节中我们学会了如何在页面中添加一个组件以及一些基本的Angular知识,而这一节将用Angular来创建一个单页应用(SPA).这意味着,取代我们之前用Express在服务端运行整个网站逻辑的方式(jade.路由都需要在服务端编译),我们将用Angular在客户端浏览器上跑起来.PS:在正常的开发流程上,我们可能不会在服务器端创建了一个网站,然后又用SPA重建它.但从学习的角度来说这还不错,这样掌握了两种构建方式. 上一节所有Angular相关的代码都在一个js里面,这不便管理和维护,这一

好程序员web前端分享如何构建单页Web应用

好程序员web前端分享如何构建单页Web应用,首先我们来看一看单页应用是什么?所谓单页应用,指的是在一个页面上集成多种功能,甚至整个系统就只有一个页面,所有的业务功能都是它的子模块,通过特定的方式挂接到主界面上.它是AJAX技术的进一步升华,把AJAX的无刷新机制发挥到极致,因此能造就与桌面程序媲美的流畅用户体验. 其实单页应用我们并不陌生,很多人写过ExtJS的项目,用它实现的系统,很天然的就已经是单页的了,也有人用jQuery或者其他框架实现过类似的东西.用各种JS框架,甚至不用框架,都是可

单页web应用(SPA)的简单介绍

单页 Web 应用 (single-page application 简称为 SPA) 是一种特殊的 Web 应用.它将所有的活动局限于一个Web页面中,仅在该Web页面初始化时加载相应的HTML.JavaScript 和 CSS.一旦页面加载完成了,SPA不会因为用户的操作而进行页面的重新加载或跳转.而是利用 JavaScript 动态的变换HTML的内(采用的是div切换显示和隐藏),从而实现UI与用户的交互.由于避免了页面的重新加载,SPA 可以提供较为流畅的用户体验.得益于ajax,我们

使用 AngularJS 开发一个大规模的单页应用(SPA)

本文的目标是基于单页面应用程序开发出拥有数百页的内容,包括认证,授权,会话状态等功能,可以支持上千个用户的企业级应用. 下载源代码 介绍 (SPA)这样一个名字里面蕴含着什么呢? 如果你是经典的Seinfeld电视秀的粉丝,那么你一定知道Donna Chang这个名字.Jerry跟Donna见面,Donna其实不是华人,但是却因在谈论其对中国的固有印象比如在针灸上的兴趣,以及偶然的一次单词发音带上了点儿中文口音,她将自己末尾的名字缩成了Chang Donna 在电话上同George的母亲交谈,(

【读书笔记】WebApi 和 SPA(单页应用)--knockout的使用

Web API从MVC4开始出现,可以服务于Asp.Net下的任何web应用,本文将介绍Web api在单页应用中的使用.什么是单页应用?Single-Page Application最常用的定义:一个最初内容只包含html和JavaScript,后续操作通过Restful风格的web服务传输json数据来响应异步请求的一个web应用.SPA的优势就是少量带宽,平滑体验,劣势就是只用JavaScript这些平滑的操作较难实现,不像MVC应用,我们可以异步form,partview.不用担心,我们

前端 SPA 单页应用数据统计解决方案 (ReactJS / VueJS)

前端 SPA 单页应用数据统计解决方案 (ReactJS / VueJS) 一.百度统计的代码: UV PV 统计方式可能存在问题 在 SPA 的前端项目中 数据统计,往往就是一个比较麻烦的事情,React 和 Vue 也是一样. 在 发现问题之前,我们得来思考下 百度统计的 统计原理 是什么? 1-1: 百度统计代码 var _hmt = _hmt || []; (function () { var hm = document.createElement("script"); hm.