不做小透明--React單頁應用動態生成meta tag及測試

【README.md】

Hi 我是栗子君,一枚身在美帝的小程序員。

我工作的公司加上老闆一共有五個人:老闆邁叔,維持著一切事物讓業務不至於垮掉的產品經理田田,顏值擔當吉米還有吐槽擔當的我,還有剛剛加入的酷炫小哥DJ。

就像銀魂里的萬事屋,我們經常會接到各種客戶奇奇怪怪的委託,每天都要面對不一樣的技術問題。生活在充滿挑戰的環境里的我決定開通這個專欄,來記錄每一個挑戰,每一次嘗試,每一種解決方案,希望能夠幫到遇到同樣問題的你(圍笑)。

正確打開方式:

【太長不看】--> 沒時間或者沒興趣閱讀全文的話也沒關係,只要看【太長不看】標籤就可以 get到要點。

【參考鏈接】--> 研究問題的時候參考的材料鏈接。

【請講人話】--> 會對一些術語做出盡量通俗的解釋,如果有另外需要解釋的術語請在評論區 留言~我會在文中更新

歡迎轉發!歡迎點贊!轉載請聯繫專欄作者授權。

【序】

最近我們在用react開發一個健康檔案管理的單頁應用。前一陣客戶大大收購了一批健康方面的文章想要通過這個應用智能推送給用戶,隨著開發的進行,最近客戶大大又發來了新的設計稿,要求一鍵分享文章到社交網路。

心想著「不就在頁面上加幾個meta tag嘛」,果安裝了react-helmet,動態抓取數據然後注入到head里.

class ArticleDetail extends React.Component{n//...nrender(){n <div className="feedDetailContainer">n <Helmet>n <meta property="og:url" content={this.state.url} />n <meta property="og:type" content="article" />n <meta property="og:title" content={this.state.title} />n <meta property="og:description" content={this.state.pushmsg} />n <meta property="og:image" content={this.state.imgurl} />n </Helmet>n //...n </div>n }n}n

然鵝事情並不簡單!

運行之後才發現,雖然meta tag被成功注入到head里了,可是facebook的爬蟲又不會運行頁面上的javascript,在爬蟲眼裡,載入好內容和meta tag的頁面只是最基本的html和react的root element。

【太長不看】

兩套路由,如果檢測到是爬蟲發出的請求,返回伺服器渲染的靜態頁面,其他情況正常返回;本地測試使用localtunnel。

【伺服器渲染】

經過一番研究後,發現解決方案大概分為兩個流派:預先渲染(pre-render)派和伺服器渲染(server-side render)派。預先渲染就是在build的階段根據js生成靜態html頁面,當遇到請求的時候直接返回生成好的頁面;而伺服器渲染則是在遇到請求後在伺服器端抓取數據,渲染html,再返回生成的html。由於文章的數目比較大,預先渲染後靜態文件也會特別多,所以我決定採用伺服器渲染的方法。如果對預先渲染感興趣的話,react-snapshot和react-snap值得試一試~

伺服器渲染的邏輯很簡單:兩套路由,如果檢測到是爬蟲發出的請求,返回伺服器渲染的靜態頁面,其他情況正常返回。

首先就是要判斷請求是否是爬蟲發出的。各大社交網路的爬蟲都是有名字的,包含在user-agent里,網上搜facebook/twitter crawler user agent 就可以找得到。

我們用的是express,在app.js里加上:

app.use(function(req,res,next) { n var ua = req.headers[user-agent];n if (/^(facebookexternalhit)|(Facebot)|(Twitterbot)|(Pinterest)/gi.test(ua)) { n console.log(ua,is a crawler)n }else{n next()n }n)}n

然後創建一個專門用來被爬的html模板:

<html>n <head>n <meta property="og:url" content="{{url}}" />n <meta property="og:type" content="article" />n <meta property="og:title" content="{{title}}" />n <meta property="og:description" content="{{description}}" />n <meta property="og:image" content="{{imgurl}}" />n </head>n</html>n

接到請求後抓取數據並渲染模板:

app.use(function(req,res,next) { n var ua = req.headers[user-agent];n if (/^(facebookexternalhit)|(Facebot)|(Twitterbot)|(Pinterest)/gi.test(ua)) { nn //async call to get datan getArticle(article,function(err,article){n if(err||!article){n res.send(500)n }else{n fs.readFile("route/to/metaTemplate.html",function(err,data){n var str = data.toString();n if(article){n str = str.replace({{title}},article.title);n str = str.replace({{pushmsg}},article.pushmsg);n str = str.replace("{{url}}",article.url);n str = str.replace("{{imgurl}}",article.imgurl);n }nn res.send(str);n })n }n })n }else{n next();n }n }else{n next(); n }n n });n

這樣就能為各個網站的爬蟲提供一個只包含meta tag的html頁面,反正他們也只關心meta tag。

【本地測試】

如果是像我一樣用localhost在本地開發的話,會發現寫完了還要部署到伺服器上才能測試代碼管不管用。有沒有什麼辦法能讓爬蟲們也爬一下本地伺服器呢?

我試了兩個內網穿透服務,Ngrox和Localtunnel。網上貌似有很多ngrox的帖子,貌似功能很強大的樣子,可惜貌似從2017年免費版就不能用來測試爬蟲了。倒是localtunnel安裝方便,簡單好用。在terminal里運行:

npm install -g localtunneln

然後在localhost運行你的app,假如埠是3000,再在terminal里運行

lt --port 3001n

就會看到:

your url is: https://tzmthicxos.localtunnel.men

用這個url就可以到developers.facebook.com 這樣的線上debugging tool里去測試啦~

【參考鏈接】

Adding Social Sharing in a Node.js Single-Page Application

對全棧開發感興趣的話請關注我的專欄 全棧萬事屋。


推薦閱讀:

網站馬太效應問題,小網站如何避免?
如何查詢自己網站的外鏈、收錄、PR、權重?
網站優化誰會啊?

TAG:搜索引擎优化SEO | React | SPASinglePageApp |