当前位置: 首页 > 后端技术 > Node.js

一个变相的服务端渲染系统

时间:2023-04-03 23:59:02 Node.js

前端发展到现在,SPA应该已经被广泛使用了。遗憾的是,我们的速度很快,但其他搜索引擎爬虫和用户的浏览器设备却跟不上。我辛辛苦苦编写的单页应用程序,在与浏览器的SEO兼容性方面却一头雾水。想必很多同学都想过服务端渲染。但是,如果你看vue的文档,react到服务端渲染,你可能就被唬住了。之前写的东西不能无缝迁移。而且,只要有一个项目,就需要运行一套节点服务。当然,架构能力较好的朋友可以做好集中管理。所以,当我想在项目中使用vue或者react的时候,遇到这些非常大的阻力。就在我头疼的时候,我发现了一个新的方法。不久前,一位同事在群里分享了puppeteer。它的GitHub介绍如下:Puppeteer是一个Node库,它提供了一个高级API来通过DevToolsProtocol控制headlessChrome。它还可以配置为使用完整(非无头)Chrome。大意是一个节点库,它提供了一个用于操作HeadlessChrome的API。更具体地说,可以通过一些API,在node环境中“模拟”真实的chrome访问页面,模拟用户操作,获取DOM在上面。那么既然它可以像真正的Chrome一样访问页面并输出渲染后的html,为什么我不能用它来为我们做服务端渲染呢?想象一下,我们有这样一个服务A,它可以像chrome一样访问一个指定的页面,并将最终页面上的dom返回给你。而你原来的业务服务器B只需要判断是爬虫还是低版本IE就可以访问,调用服务,获取html,返回html给用户,实现了服务端渲染。大致的流程图如下:有了这样的想法之后,我们就想办法去实践。实践的过程就是解决问题的过程。仔细想想,我们会遇到以下问题:Q1:即使模拟Chrome请求一个页面,视图也往往是异步渲染的。比如先请求列表接口,获取数据,再渲染列表DOM。这个时候,我们是没有办法控制的。那么这个服务应该什么时候返回加载的HTML呢?遇到问题可以先看看别人的文档PuppeteerAPI。幸运的是,我们找到了以下方法:page.waitFor(selectorOrFunctionOrTimeout[,options[,...args]])page.waitForFunction(pageFunction[,options[,...args]])page.waitForNavigation(options)page。waitForSelector(selector[,options])我们可以通过一些设置让页面只在特定条件下返回。例如设置page.waitForSelector('#app'),只有当页面上出现id="app"的元素时才返回html内容。或者通过设置page.waitForFunction('window.innerWidth<100'),当页面宽度小于100px时,返回此时的html内容。通过这些方法,我们可以有办法控制我们希望什么时候以及什么样的页面丢失给爬虫。Q2:IE用户流量比较大怎么办?虽然我们使用这样的系统,但是有些不能渲染页面的浏览器(IE9以下)可以渲染页面。但是这样的请求过程相对来说会比较耗时,不是很合理。那么我们只要做一个缓存系统就可以了。每次请求时,都会判断是否有本次请求的未过期缓存HTML。如果存在则直接返回缓存的HTML,否则请求页面并保存缓存。Q3:虽然页面显示出来了,但IE用户还是不能做一些JS交互。我们无法在服务层解决这个问题,但是我们可以在前端做更友好的交互提示。如果判断用户使用的是低版本IE,则会出现小提示,提示用户下载更好的浏览器以获得更好的体验。Q4:单页应用的路由多采用anchors(hash方式),服务端无法获取hash参数,因此无法请求到正确的页面。有办法解决这个问题,可以使用HTMLHistory方式的路由,比如vue-router,然后路由链接最好以生成标签+href的方式写在页面中,而不是js跳转之后onclick,让爬虫可以最好的抓取整个站点页面。当问题可以解决的时候,我们就可以开始真正的编码了。Papapa,papapa=>SSR-SERVICE不错,以后就好了。在不到200行的代码中,我们实现了一个通用的、面向服务的、单页面应用服务端渲染方案。