詳解在不使用ssr的情況下解決Vue單頁(yè)面SEO問(wèn)題
遇到的問(wèn)題:
近來(lái)在寫(xiě)個(gè)人博客的時(shí)候遇到了大家可能都會(huì)遇到的問(wèn)題
Vue單頁(yè)面在SEO時(shí)顯得很無(wú)力,尤其是百度不會(huì)抓取動(dòng)態(tài)腳本
Vue-Router配合前后端分離無(wú)法讓meta標(biāo)簽在蜘蛛抓取時(shí)動(dòng)態(tài)填充
Vue單頁(yè)面又是大勢(shì)所趨,寫(xiě)起來(lái)也不止是一個(gè)爽,當(dāng)然也可以選擇多頁(yè)面
但即使是多頁(yè)面在面對(duì)文章和文檔時(shí)候也不可能說(shuō)給每篇文章生成個(gè)Vue頁(yè)面
SSR當(dāng)然能解決這個(gè)問(wèn)題,但是仔細(xì)想想SSR不就跟以前的.php頁(yè)面一樣了么
都是預(yù)先拉取所有數(shù)據(jù)然后填充返回給瀏覽器,需要多消耗服務(wù)器資源,而且配置繁瑣
當(dāng)然預(yù)渲染也不能解決這個(gè)問(wèn)題
那么問(wèn)題來(lái)了,我只是想讓百度抓取下我的動(dòng)態(tài)文章,但是配置個(gè)繁瑣的SSR并不是最好選擇
我的解決辦法:
既然只是想讓百度抓取下我的動(dòng)態(tài)文章,其實(shí)就是讓蜘蛛抓取我的靜態(tài)頁(yè)面時(shí)候,html的meta標(biāo)簽是已經(jīng)填充好的
那么就很簡(jiǎn)單了,我們只需要實(shí)現(xiàn)一個(gè)極其簡(jiǎn)單的閹割版的SSR不就好了么
PS:我百度了很久沒(méi)有找到相關(guān)的文章,不知道是不是我百度的姿勢(shì)不對(duì)😅
具體思路:
因?yàn)槲业姆?wù)器后端語(yǔ)言是php,service是nginx,所以我這里展示的所有后端代碼都是基于php,大家當(dāng)然可以選擇nodejs或者其他的語(yǔ)言去實(shí)現(xiàn),這里提供個(gè)簡(jiǎn)單的思路
上面說(shuō)到我們要實(shí)現(xiàn)個(gè)閹割版SSR,其實(shí)就是在服務(wù)器有請(qǐng)求過(guò)來(lái)的時(shí)候在靜態(tài)html的meta標(biāo)簽上填充好數(shù)據(jù)然后返回給請(qǐng)求端
這里的實(shí)現(xiàn)都是基于已經(jīng)構(gòu)建好的Vue單頁(yè)面,所以請(qǐng)先構(gòu)建好一個(gè)Vue單頁(yè)面
先把構(gòu)建好的dist下的index.html改造下
在頂部將變量拿取到,因?yàn)榻涌诙际乾F(xiàn)成的,所以偷個(gè)懶直接調(diào)取接口
<?php $valDescription = '前端入門(mén),進(jìn)階總結(jié)記錄,個(gè)人日志博客,分享web學(xué)習(xí)經(jīng)驗(yàn)的小窩。'; $valKeywords = 'web窩,前端,vue,js,博客,JavaScript,css,入門(mén),教程'; $valTitle = 'web窩'; /** * 發(fā)送HTTP請(qǐng)求方法 * @param string $url 請(qǐng)求URL * @param array $params 請(qǐng)求參數(shù) * @param string $method 請(qǐng)求方法GET/POST * @return array $data 響應(yīng)數(shù)據(jù) */ 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 ); /* 根據(jù)請(qǐng)求類(lèi)型設(shè)置特定參數(shù) */ 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('不支持的請(qǐng)求方式!'); } /* 初始化并執(zhí)行curl請(qǐng)求 */ $ch = curl_init(); curl_setopt_array($ch, $opts); $data = curl_exec($ch); $error = curl_error($ch); curl_close($ch); if($error) throw new Exception('請(qǐng)求發(fā)生錯(cuò)誤:' . $error); return $data; } //分割當(dāng)前請(qǐng)求的路徑 $urlExp = explode('/',$_SERVER['REQUEST_URI']); //如果當(dāng)前的路徑是文章內(nèi)容 if(count($urlExp)>2 && $urlExp[1] == 'article'){ //請(qǐng)求當(dāng)前文章的標(biāo)題和描述 $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; } ?>
將拿到的數(shù)據(jù)輸出到meta標(biāo)簽上
<meta name="description" content="<?php echo $valDescription; ?>"/> <meta name="keywords" content="<?php echo $valKeywords; ?>"/> <title><?php echo $valTitle; ?></title>
然后把文件名改為index.php
寫(xiě)的很糙,反正就只有這一個(gè)功能,先扔到這
我的service是nginx,Vue-Router是history模式,所以當(dāng)有html請(qǐng)求過(guò)來(lái)的時(shí)候我把所有原先轉(zhuǎn)向index.html的請(qǐng)求都轉(zhuǎn)向到了index.php
這樣就實(shí)現(xiàn)了個(gè)閹割版的SSR
效果就像這樣 web窩
每篇文章刷新的時(shí)候相應(yīng)的meta標(biāo)簽都會(huì)提前填充好數(shù)據(jù)
配合nginx實(shí)現(xiàn)Vue-Router的history模式
當(dāng)然只有history模式才有SEO的意義
只需要將nginx配置里原先轉(zhuǎn)向index.html的地方改為index.php即可,Apache同理
location / { index index.php; alias /var/www/html/blog/; try_files $uri $uri/ /index.php; }
關(guān)于后端接口請(qǐng)求的問(wèn)題
因?yàn)槲易约壕鸵慌_(tái)服務(wù)器,后端語(yǔ)言是php
php所用的框架也需要偽靜態(tài)
所以我的解決方式是用nginx配置根據(jù)二級(jí)域名,去代理所訪問(wèn)的路徑
類(lèi)似靜態(tài)資源訪問(wèn)的都是cdn的二級(jí)域名,接口的請(qǐng)求訪問(wèn)的都是api的二級(jí)域名
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; }
當(dāng)然你可以簡(jiǎn)單的用請(qǐng)求的路徑去配置
server { listen 80; listen 443 ssl; server_name cdn.linkvall.cn; root /var; location ~ ^/api/ { alias /var/api; } location ~ ^/blog/ { alias /var/blog/; } }
這樣就可以把各自的資源路徑區(qū)分開(kāi)
寫(xiě)在最后
本來(lái)是打算用nodejs實(shí)現(xiàn)的,寫(xiě)一個(gè)npm包,跑一個(gè)node進(jìn)程,然后nginx把請(qǐng)求反向代理到node端口,這樣看上去更優(yōu)雅
不過(guò)轉(zhuǎn)念一想我的后端是php,直接代理到這個(gè)php文件可以省去寫(xiě)npm包的時(shí)間,就是構(gòu)建好的html還要每次都更改下有一點(diǎn)點(diǎn)費(fèi)勁,而且不優(yōu)雅
這里更多的是提供一個(gè)思路,后面有時(shí)間了或許我會(huì)寫(xiě)一個(gè)npm包優(yōu)雅的實(shí)現(xiàn)它
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue中封裝axios并實(shí)現(xiàn)api接口的統(tǒng)一管理
這篇文章主要介紹了vue中封裝axios并實(shí)現(xiàn)api接口的統(tǒng)一管理的方法,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下2020-12-12vue后臺(tái)返回格式為二進(jìn)制流進(jìn)行文件的下載方式
這篇文章主要介紹了vue后臺(tái)返回格式為二進(jìn)制流進(jìn)行文件的下載方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06python虛擬環(huán)境 virtualenv的簡(jiǎn)單使用
virtualenv是一個(gè)創(chuàng)建隔絕的Python環(huán)境的工具。這篇文章主要介紹了python虛擬環(huán)境 virtualenv的簡(jiǎn)單使用,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01Vue項(xiàng)目中如何運(yùn)用vuex的實(shí)戰(zhàn)記錄
如果說(shuō)是JQuery是手工作坊,那么Vue.js就像是一座工廠,雖然Vue.js做的任何事情JQuery都可以做,但無(wú)論是代碼量還是流程規(guī)范性都是前者較優(yōu),下面這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目中如何運(yùn)用vuex的相關(guān)資料,需要的朋友可以參考下2021-09-09關(guān)于Vue中使用alibaba的iconfont矢量圖標(biāo)的問(wèn)題
這篇文章主要介紹了Vue使用alibaba的iconfont矢量圖標(biāo)的問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12vue圓環(huán)百分比進(jìn)度條組件功能的實(shí)現(xiàn)
在一些頁(yè)面設(shè)置進(jìn)度條效果給人一種很好的體驗(yàn)效果,今天小編教大家vue圓環(huán)百分比進(jìn)度條組件功能的實(shí)現(xiàn)代碼,代碼超級(jí)簡(jiǎn)單啊,感興趣的朋友快來(lái)看下吧2021-05-05vue.js this.$router.push獲取不到params參數(shù)問(wèn)題
這篇文章主要介紹了vue.js this.$router.push獲取不到params參數(shù)問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03