搜索引擎优化(Search engine optimization,简称SEO),指为了提高网页在搜索引擎天然搜索结果中(非商业性推广结果)的收录数量以及排序位置而作的优化行为,是为了从搜索引擎中得到更多的免费流量,以及更好的展示形象。javascript
SEM(Search engine marketing,搜索引擎营销),则既包括了SEO,也包括了付费的商业推广优化。css
本文主要介绍的是前端如何在代码上作SEO以及单页项目如何实现SEO。前端
要了解SEO,首先得了解搜索引擎的工做原理,其原理是比较复杂,流程简化以下:vue
通常爬虫抓取页面内容是先从一个页面出发,从中提取出其余页面的连接,而后看成下一个请求的对象,一直重复这个过程。因此要有良好的SEO,须要你在各大网站上拥有外链,这样会提升你的网站被搜索引擎爬虫的概率。java
爬虫拿到HTML以后,就会对其内容进行分析。通常须要进行去杂、分词、简历索引数据库。什么是索引数据库呢?简单地说就是记录一个词在哪些文档中出现、出现次数、出现的位置等等。为何要简历索引数据库呢?是为了快速查找。node
搜索会根据你输入的关键词,分别查询其对应的索引数据库,并对结果进行处理和排序。webpack
网站结构要清晰。通常网站的结构是树形的,通常分为三个层次:首页 → 频道页(列表页) → 文章页(详情页)。nginx
网站的结构要扁平。结构层数越少越好,通常不要超过三层,搜索引擎通常到了第三层就不想继续深刻地爬取了。多数的网站,例如掘金、雪球等,他们的网站结构是两层,他们的首页和频道页是同一个页面。git
页面应该要有简明的导航。导航可让搜索引擎知道网站的结构,也可让搜索引擎知道当前页面在网站结构所在的层次。 建议:github
alt
属性告知搜索引擎连接的指向。规范、简单、易理解的URL能让搜索引擎更好地抓取内容。建议:
Sitemap 可通知搜索引擎他们网站上有哪些可供抓取的网页,以便搜索引擎能够更加智能地抓取网站。
搜索引擎爬行网站第一个访问的文件就是robots.txt。在这个文件中声明该网站中不想被蜘蛛访问的部分,这样,该网站的部分或所有内容就能够不被搜索引擎访问和收录了,或者能够经过robots.txt指定使搜索引擎只收录指定的内容。
不一样的返回码,搜索引擎的处理逻辑是不同的。
title是告诉搜索引擎网页的主要内容。
百度建议描述:
description是对网页内容的精练归纳。这个标签存在与否不影响网页权值,只会用作搜索结果摘要的一个选择目标。 百度推荐作法:
HTML语义化是用标签和属性来描述内容。因此HTML语义化是SEO的基石。通常建议:
关于这部分的内容比较多,本人有一篇笔记《HTML语义化》
目前,对于SEO支持比较好的项目方案是采用服务端渲染。因此若是项目有SEO需求,那么比较好的方案是服务端渲染。
若是你已经采用了先后分离的单页项目,而你的网站内容不须要AJAX去获取内容和展现内容,那么能够试试 prerender-spa-plugin 这个插件,这个插件是一个webpack插件,能够帮助你在打包过程当中经过无头浏览器去渲染你的页面,并生成对应的HTML。固然这个方案适合你的路由是静态的,而且路由数量非海量。
若是你的内容是AJAX动态获取的,那么vue单页项目能够试试 prerender ,这个是一个预渲染服务,能够帮你经过无头浏览器渲染页面,并返回HTML。这个方案和prerender-spa-plugin
很类似,都是经过无头浏览器去渲染页面,不一样的是渲染的时机,prerender-spa-plugin
是在打包过程当中渲染,注定了其只能渲染静态路由,而prerender
是在请求时渲染,因此能够渲染动态的路由。下面我重点介绍一下prerender
方案。
一、安装
$ npm install prerender
复制代码
二、启动服务 server.js
const prerender = require('prerender');
const server = prerender();
server.start();
复制代码
三、测试
http://localhost:3000/render?url=https://www.example.com/
复制代码
通过上面三个步骤,你就已经启动一个预渲染服务,而且会返回"www.example.com/"的内容,整个过程仍是比较简单的。其github官网上面还介绍了它的许多中间件(Middleware),例如prerender-node (Express)
、nginx.conf
等,那么这个和 prerender 是什么关系呢?是否直接使用中间件就能够呢?下面介绍prerender是如何工做的吧。
首先服务端接收到一个页面的请求,而后判断这个请求是否来自搜索引擎的爬虫,若是不是,则直接返回单页项目的HTML,按照普通单页项目的工做模式(客户端渲染),若是是,则把请求转发给prerender服务,prerender服务会经过无头浏览器进行预渲染,渲染完成把内容返回,这样爬虫就能够拿到有内容的HTML了。prerender中间件就是用来判断请求是否来自搜索引擎爬虫和转发请求的。
值得注意的是,prerender服务是不包含无头浏览器的,因此须要自行安装chrome浏览器。所以,整个方案运行须要三部分:
那么prerender服务是怎么知道页面渲染已经完成的呢? Prerender服务经过计算未完成的请求数量,来肯定页面什么时候完成加载。一旦未完成的请求数达到零,服务会等待一段时间(默认500ms),而后保存HTML。
通过实践,请求一个通过prerender渲染的页面是时间,快的时候约2s,慢的时候会长达8s。通常来讲,请求时间在3s之内是最好的。因此我从如下几个方面入手,探索prerender的优化方法。
影响prerender渲染时间的资源主要有js请求资源和api请求资源,api请求时间通常由后端决定,因此我考虑的是如何减小js资源请求时间。通常prerender服务渲染的资源请求地址是由页面请求URL决定的,因此通常是线上的地址,若是咱们把prerender服务部署在网站的服务器上,让prerender服务请求资源走本地,那么就能够缩短资源的请求时间了。
若是你的线上服务是开启了CDN的话,那么资源走本地还有一个好处,就是能够节省CDN流量。
prerender提供了一些自定义的选项
pageDoneCheckInterval
:这个参数是prerender检查页面请求是否完成的定时器时间,默认是500ms,即每500ms检查未完成的请求数量是否为零,我将其修改成100ms,提升其检查的频率。
waitAfterLastRequest
:这个参数是最后一个请求完成以后等待的时间,默认是500ms,主要是请求完成以后,页面更新渲染须要时间,当即返回的话,可能请求的数据来不及渲染,我将时间修改成200ms。
添加httpHeaders这个插件,能够更改返回的HTML的HTTP状态码,添加方式以下
var prerender = require('prerender');
var server = prerender()
server.use(prerender.httpHeaders());
server.start();
复制代码
prerender经过识别在<head>中的<meta>标签来设置页面返回的HTTP状态码。
<meta name="prerender-status-code" content="404">
复制代码
若是你须要设置301重定向,能够这样作
<meta name="prerender-status-code" content="301">
<meta name="prerender-header" content="Location: http://www.xxx.com">
复制代码
prerender是根据未完成的请求数来判断是否渲染结束的。可是咱们给搜索引擎返回的HTML只须要渲染经过js动态增长的DOM,其实不须要渲染css或者渲染接口返回的图片的,咱们来看下prerender在渲染中是否会请求这些资源。 prerender能够开启是否打印请求,开启方式以下:
var server = prerender({
logRequests: true
});
复制代码
开启以后就能够在控制台看到请求了,请求里面是包含css和图片资源的。
2019-07-17T04:34:03.180Z - 47 http://xxx.com/css/chunk-f4a02584.da8dca38.css
2019-07-17T04:34:03.180Z {
source: 'network',
level: 'error',
text: 'Failed to load resource: net::ERR_INVALID_ARGUMENT',
timestamp: 1563338043130.37,
url: 'http://xxx.com/wefid/css/chunk-f4a02584.da8dca38.css',
networkRequestId: '1000039068.65'
}
2019-07-17T04:34:03.924Z + 3 http://xxx.com/img/erweima_wx.a84d82ef.jpg
2019-07-17T04:34:03.924Z + 4 http://xxx.com/img/erweima_wb.06971584.png
复制代码
为何prerender要等待这些资源呢?由于prerender服务还有一个强大的功能,那就是Prerender.com
,其能够经过一个接口给你返回以下的东西:
很明显,这些功能是须要加载你所需的CSS或图片资源的,否则网页显示有问题。这个时候,若是你只须要知足SEO需求而不须要Prerender.com
的功能的话,那么blockResources
插件就能够派上用场了。插件添加方式以下:
var prerender = require('prerender');
var server = prerender()
server.use(prerender.blockResources());
server.start();
复制代码
使用blockResources
插件以后,图片资源和字体资源会被abort(舍弃)。
若是你想更细粒化地控制prerender的返回时机,提早结束或者延后结束,那么可使用这个标志window.prerenderReady
。
首先须要设置window.prerenderReady
为false,prerender在检测到window.prerenderReady
为false
以后,会等待你设置为true
再返回结果。
<script> window.prerenderReady = false; </script>
复制代码
当你渲染完成以后,通常在接口请求完成并渲染完成以后
window.prerenderReady = true;
复制代码
这样你就能够更加自由地控制渲染结束的时机。
缓存这里有两个方面,一方面是HTTP缓存(浏览器缓存),另外一方面是渲染结果缓存。
首先HTTP缓存可让prerender服务不用频繁地发起资源请求,节省传输时间。这个我就不展开将,我想讲的是渲染结果缓存。prerender中间件提供了两种缓存方式, redis 或者 memcached ,以redis为例:
$ npm install redis
复制代码
var redis = require("redis"),
client = redis.createClient();
prerender.set('beforeRender', function(req, done) {
client.get(req.url, done);
}).set('afterRender', function(err, req, prerender_res) {
client.set(req.url, prerender_res.body)
});
复制代码
你能够经过 beforeRender 和 afterRender 这两个钩子进行细粒化地控制,对于内容变化频繁的不缓存或缓存时间短,对于内容变化不频繁的设置长时间缓存。开启缓存不只能够加速返回时间,还能够减轻服务器的压力。
统计和监控能够放在中间件的 afterRender 中进行。
prerender.set('afterRender', function(err, req, prerender_res) {
if(err){
// 这里是错误监控代码
// ...
// return
}
let {headers: req_headers, originalUrl} = req
let {headers: res_headers, body} = prerender_res
// 这里是统计代码,能够保存请求和返回的相关信息
})
复制代码
经过以上的优化方法(除了自定义渲染结束时间和开启缓存),我已经将HTML的请求时间稳定在2.5s左右。
以上就是我想讲的关于前端编码SEO的所有内容,总而言之,就是