Node微信公众号开发 封装request和获取access_token

三世轮回 提交于 2020-02-25 20:57:48

按照上一篇的说明,我们现在已经做好了和微信公众平台的对接工作,接下来我计划首先实现请求 access_token 的功能。

在开发过程中并非照搬教程内容,自己有所修改,主要的修改内容是在文件结构以及数据传输上。

原教程目录结构:

  • material(素材文件夹)
  • wechat(核心文件夹)
    • access_token.json(用于请求 access_token )
    • menu.json (自定义菜单目录文件)
    • msg.js (涉及所有的被动回复种类)
    • wechat.js (核心文件,其中包括调用自定义菜单、自定义回复等功能)
  • app.js(入口文件)
  • config.json(基础配置数据,其中包括 appid、appScrect 以及各种的请求地址)

我的目录结构:

  • material(素材文件夹)
  • app.js(入口文件)
  • config.json(基础配置数据以及动态存储的 access_token 数据)
  • request.js(封装的 post 和 get 方法)
  • accessToken.js(用于请求 access_token )
  • createMenu.js(用于生成自定义菜单)
  • replyType.js(涉及所有的被动回复种类)
  • reply.js(自定义回复)

个人认为,至少我的目录结构拆的更细化,至于好坏我不敢说。


封装 request 方法

其实 Node.js 开发微信公众号,无非就是按照文档去请求官方接口地址。所以在真正开发前,我们需要封装一套请求方法(自己尝试过利用 aoxis ,但是没有处理好对于 formData 的处理,只能未果),这里使用 request 模块实现请求。

var request = require('request') // 引入 request 组件

// 封装一个get请求方法
exports.get = (url) => {
	return new Promise((resolve, reject) => {
		request(url, (error, response, body) => {
			if (!error && response.statusCode == 200) {
				console.log('get request success')
				resolve(body)
			} else {
				console.log('get request fail')
				reject(error)
			}
		})
	})
}

// 封装一个post请求方法
exports.post = (url, data) => {
    // 这里需要判断 data 数据类型,因为自定义菜单和图片上传的数据格式有异,会导致报错
	return new Promise((resolve, reject) => {
		var form = {
			url: url
		}
		if (typeof data == 'string') {
			form.body = data // 如果数据格式为字符,则菜单数据通过 body 提交给接口
		} else {
			form.formData = data // 否则数据通过 formData 提交给接口(这里指的是上传图片接口)
		}
		request.post(form, (error, response, body) => {
			if (!error && response.statusCode == 200) {
				console.log('post request success')
				resolve(body)
			} else {
				console.log('post request fail', error)
			}
		})
	})
}

通过 Promise 我们可以在后期调用时更方便的处理请求结果。

这里需要特别注意一下,就是需要对 post 数据类型进行判断,因为按照目前的代码涉及 post 请求的地方有两个,分别是回复图片素材以及创建自定义菜单,自定义菜单的数据为 json 格式可以直接通过 body,而在回复素材则数据格式为 object 需要提交 formData。

这个区别曾经困扰了一段时间。

获取 access_token

了解一下 access_token 是什么?

  • 它是公众号的全局唯一接口调用凭据;
  • 有效期目前为2个小时,需定时刷新;
  • 重复获取将导致上次获取的 access_token 失效;
  • 它的请求方式为 get
  • 它的请求地址是 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

我们可以使用 [微信公众平台测试账号] 提供的测试 appidappsecret 将地址拼接成正确请求地址,之后之前前文封装好的 get 方法请求。

这里我是用了 fs 模块将请求到的 access_token 写入 config.json ,这样做我认为可以保证所有相关配置信息都在一起,方便调用。

var fs = require('fs') // 引入核心模块
var request = require('./request') // 引入封装好的 request 模块

module.exports = (config) => {
  return new Promise((resolve, reject) => {    
    var currentTime = new Date().getTime() // 获取当前时间戳

    // 拼接请求地址
    var url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + config.appId + '&secret=' + config.appScrect

    // 若 config 中 accesstoken 为空或者过期则需要重新请求
    if (config.setAccessToken.accessToken === '' || config.setAccessToken.time < currentTime) {
      request.get(url).then((response) => {
        var result = JSON.parse(response)
        
        // 修改 config 数据
        config.setAccessToken.accessToken = result.access_token
        config.setAccessToken.time = new Date().getTime() + (parseInt(result.expires_in) - 200) * 1000 // accesstoken 过期时间

        // 将更新后的 config 写入文件
        fs.writeFileSync
        fs.writeFile('./config.json', JSON.stringify(config), (error) => {
          if (error) {
            console.log('update accessToken fail')
            reject(error)
          }
          console.log('update accessToken success')
          
          resolve(response.access_token) // 将 accesstoken 导出
        })
      }).catch((error) => {
        // 请求失败
      	console.log('request accessToken fail', error)
        reject(error)
      })
    } else {
      // 若本地 access_token 未失效则直接导出
      console.log('get accessToken success')
      resolve(config.setAccessToken.accessToken)
    }
  })
}

到此为止我们前期工作都已告结,我会在后两篇日志中更新自定义菜单以及自定义回复,还望各位客观莅临。


文章已同步我的个人博客:《Node微信公众号开发 封装request和获取access_token


相关文章:


资料参考:

本文由博客一文多发平台 OpenWrite 发布!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!