puppeteer在开发过程当中的实践

上篇文章咱们谈了一下puppeteer是什么,以及具体能作什么,但文中谈到的在咱们平常开发中并不经常使用到,截图咱们有截图工具、前端自动化测试有phantomjs、selenium。不只如此,为了SEO,前端基本都会作SSR,爬取这样的页面的话python得益于强大的模块,具备得天独道的优点。也许有人会问,那对于某些后台管理系统,是没有作SSR的,此时puppeteer的优点不就体现出来了吗?对于此种状况,首先,爬管理系统的数据的话须要有帐号密码,咱们没有。那若是是咱们本身的系统的话,数据都是本身的,我还须要爬吗?前端

额。。。。node

pupueteer看来彷佛并无想象中的那么强大。但实际状况下并不是如此,虽然有些功能以前存在的一些框架也能作到,但毕竟对于咱们前端开发来讲,要想掌握新的技术就须要去学习新的语言,这样的话成本就很大了。python

pupueteer提供了简洁的API和丰富的接口,并且其是一个nodejs库,因此从学习角度来说对前端很友好,上手快。接下来就来具体描述一个在实际开发过程当中使用puppeteer的场景。react

在咱们公司前端开发的过程当中,大部分项目要去接CAS,什么是CAS呢,走你,其目的是为了获取COOKIE,以便于与后端进行交互。我司目前常见的场景存在三种形式。git

1.前端网关nodejs,主要用于转换dubbo协议,获取数据,其项目中会用nodejs去接casgithub

2.有些应用,服务端接口须要登陆cas后拿到回调的cookie去请求数据,而此时前端要配置代理,模拟cas登陆,拿到cookie后写在header里后端

3.有些应用,直接登陆相关应用的开发环境,而后把cookie拿过来经过document.cookie写到本地环境进行开发跨域

第一种状况由于线上须要cas登陆,暂且不表。bash

但对于后面两种状况,这里能够简单分析下,其实2和3都是在本地开发的时候拿到登陆cas后的cookie,而后在请求数据的时候把cookie带回去拿到数据。但要放到服务器的时候其实是前端把静态资源所有打包成某一个或若干个js文件(通常不会超过3个)。因此问题就变成了咱们怎么在开发环境方便的拿到登陆cas成功后的cookie。若是对于一个熟悉cas sso原理的话,其对接一下cas可能会很快,但弊端就是要新搭一个node服务,写一些登陆cas,拿cookie的流程,并且若是针对不一样权限角色的话,每次登陆新的角色,都要从新用不一样角色去登陆系统,去拿cookie(咱们在开发运维发布平台便是如此,涉及admin,运维,开发,测试,测试经理等不一样角色,每次功能有掺和都是一个痛苦的切换cas登陆拿cookie的过程); 若是对于一个不明其理的开发来讲,这无异于一枚张榜炸弹,你接口跨域我能够很简单的作下代理,cas, w**fk, 告辞.......服务器

那如何在开发环境用puppeteer作到拿cookie的过程呢?

(敲黑板) 划重点啦。

以我负责开发的运维发布平台为例, 其实现思路以下

puppeteer

代码以下:

const puppeteer = require("puppeteer");

let cookie = {
  name: "JSESSIONID",
  value: "",
  domain: "localhost",
  url: "http://localhost:3000/",
  path: "/",
  httpOnly: true,
  secure: false
};
const role = process.argv.pop();

const getRole = role => {
  return {
    a: { //系统管理员
      username: "admin",
      password: "123456"
    },
    qa1: { //测试经理
      username: "04688",
      password: "123456"
    },
    qa: { //测试
      username: "01522",
      password: "123456"
    },
    dev: { //开发
      username: "04588",
      password: "123456"
    },
    ops: { //运维
      username: "04141",
      password: "123456"
    }
  }[role];
};

class Launch {
  constructor(username, password) {
    this.username = username;
    this.password = password;
    this.flag = true;   //用来判断拦截第一次302
  }
  async init(page, browser) {
    // <!--  模拟cas登陆 -->
    const casBrowser = await puppeteer.launch();    
    const loginPage = await casBrowser.newPage();
    await loginPage.goto("CAS开发环境地址");
    await loginPage.type("#username", this.username);
    await loginPage.type("#password", this.password);
    await loginPage.click("input[type=submit]");
    await loginPage.waitFor(1000);
    const cookies = await loginPage.cookies();
    cookies.map(v => {
      if (v.name === cookie.name) {
        cookie.value = v.value;
      }
    });
    await casBrowser.close();
    // <!--  拿到cookie后,关闭该实例 -->
    
    // <!-- 打开本地环境流程 -->
    let appBrowser = browser, appPage = page;
    if (appPage) {  // 若是cookie过时,直接在该实例上setCookie,无需新开实例
      await appPage.setCookie(cookie);  
      await appPage.reload()
      this.flag = true;
    } else {
      appBrowser = await puppeteer.launch({
        headless: false,
      });
      appPage = (await appBrowser.pages())[0];  
      await appPage.setCookie(cookie); //设置cookie
      const {
        width,
        height
      } = await appPage.evaluate(() => {
        return {
          width: window.outerWidth,
          height: window.outerHeight
        };
      });
      await appPage.setViewport({
        width,
        height
      });
      await appPage.goto("http://localhost:3000/");
    }
    // <!-- 本地流程结束 -->
    
    //监听请求
    await appPage.on("response", async (res) => {
      const status = res.status();
      if (status === 302 && this.flag) {    //cookie过时后,服务接口会重定向到cas登陆页,因此只需拦截302便可知道cookie是否过时,固然也可和后端约定一个状态,如401
        this.flag = false;
        this.init(appPage, appBrowser);  //cookie过时,从新模拟登陆cas获取新的cookie
        }
    })
  }
}

const {
  username = "admin", password = "123456"
} = getRole(role) || {}  //默认登陆admin帐号

const launch = new Launch(username, password);

launch.init()

复制代码

上述setCookie是根据我司统一cookie而写,具体状况具体分析

Cookie

简单明了的完成了拿cookie的过程,省去了繁琐的设置代理去登陆cas的过程, 。至此,咱们完成了puppeteer在实际开发中的应用,大大减小了登陆,切换帐号的过程。

其实我用QuickTime录制了一段小视频,可是转换gif的时候转不了,不知道为啥,因此gif图就不传了,自行脑补哈。

大家有没有发现我在告辞后面用了7个., 皮一下确实很开心,哈哈哈 点我点我 .......

关于puppeteer ssr的场景就很少说了,通常都会在服务端作掉,关于react ssr的例子,详见 嘿嘿嘿

相关文章
相关标签/搜索