微信公众号全流程

前端技术:react+@umijs/max+antd-mobile

  1. 申请公众号(服务号+已认证)
  2. web开发者工具中绑定开发人员(该开发人员需要关注1中申请的公众号)
  3. 基本配置
    3.1 服务器配置
    URL:验证服务器(后端写的验证服务器的接口)
    后端代码:egg.js
yarn add crypto-js

const SHA1 = require('crypto-js/sha1');
	async checkSign() {
	    const { ctx, app } = this;
	    const token = app.config.wechat_config.token; // 替换为你的微信公众号的Token
	    const { signature, timestamp, nonce, echostr } = ctx.query;
	    const shasum = SHA1([ token, timestamp, nonce ].sort().join('')).toString();
	    if (shasum === signature) {
	      return echostr;
	    }
	    return 'Invalid signature';
	  }

	async validate() {
	    const { ctx, service } = this;
	    ctx.body = await service.wx.checkSign();
	}

Token: 可以自定义(后续跟微信要信息的时候使用,验证服务器的时候也需要)
服务器配置什么时候启用:
一些自定义的跟微信相关的操作:例如支付流程,自定义推送等

3.2 自定义菜单(公众号底部的菜单配置)
3.2.1 可以配置完成的带公众号基础信息的url
例如:https://open.weixin.qq.com/connect/oauth2/authorize? appid=wx8a432443c4997c0c&redirect_uri=http://gzh-dev.nangaoyun.com/equip/wechatAuth/menu?type=work&response_type=code&scope=snsapi_userinfo&state=123&connect_redirect=1#wechat_redirect
3.2.2 也可配置访问页面的地址
例如:http://www.youtianchen.cn

  1. 网页授权
    4.1 用户同意授权,获取token
    这个code是我们点击自定义菜单时,微信内部重定向到一个url,这个url里带了code

获取code(前端代码)

import { history } from "umi";
import { doFetch } from "./doFetch"; //发送请求的方法,封装了一下而已

//从网页地址中获取code
function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split("&");
  for (var i = 0; i < vars.length; i++) {
    var pair = vars[i].split("=");
    if (pair[0] == variable) {
      return pair[1];
    }
  }
  return false;
}

export default function getUserinfo(props, fn) {
  const token = localStorage.getItem("TOKENS");
  if (token && token != "undefined") {
    return;
  }
  const code = getQueryVariable("code");
  if (code) {
    alert(code);
    
    //获取access_token
    
    doFetch({
      url: "http://www.youtianchen.cn/web/authtoken",
      params: {
        code,
      },
    }).then((res) => {
      console.log('====================================');
      console.log(res);
      console.log('====================================');
      
    });
  } else {
    let uri = "http://www.youtianchen.cn"; //'http://www.sanbaodagong.com/wechat/index.html';
    window.location.href =
      "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx289794cd442ff592&redirect_uri=" +
      uri +
      "&response_type=code&scope=snsapi_base#wechat_redirect";
  }
}

4.2 前端拿到code传给后端,后端获取access_token(这个可以做各系统的绑定)

后端这里给出egg.js写出的代码:

// 判断token值从哪里获取
  async fetchAccessToken(code) {
    const { app } = this;
    const access_token = await app.redis.get('access_token');
    console.log(access_token, 'access_token');

    // redis 存在access_token
    if (!access_token) {
      const token = await this.fetchToken(code);
      return token;
    }
    // redis不存在access_token
    const istoken = await this.istoken(access_token);
    if (istoken) {
      return access_token;
    }
    const token = await this.fetchToken(code);
    return token;
  }

  // 判断token是否失效
  async istoken(token) {
    const { ctx, app } = this;
    const openid = await app.redis.get('openid');
    const res = await ctx.curl(
      `https://api.weixin.qq.com/sns/auth?access_token=${token}&openid=${openid}`,
      {
        // 必须指定 method
        method: 'GET',
        dataType: 'json',
      }
    );
    console.log(res, 'istoken');
    return res?.data?.errcode === 0;
  }

  // 获取token 定时任务
  async fetchToken(code) {
    const { ctx, app } = this;
    const appid = app.config.wechat_config.appid;
    const appsecret = app.config.wechat_config.appsecret;
    const refresh_token = await app.redis.get('refresh_token');
    const URL = code
      ? `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=${appsecret}&code=${code}&grant_type=authorization_code`
      : `https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=${appid}&grant_type=refresh_token&refresh_token=${refresh_token}`;
    const res = await ctx.curl(URL, {
      method: 'GET',
      dataType: 'json',
    });
    console.log(res, 'token_response');
    if (res.data.refresh_token) {
      await app.redis.set('refresh_token', res.data.refresh_token);
    }
    if (res.data.openid) {
      await app.redis.set('openid', res.data.openid);
    }
    if (res.data.access_token) {
      await app.redis.set('access_token', res.data.access_token);
      await this.createMenu(res.data.access_token);
      return res.data.access_token;
    }

    return null;
  }

4.3 后端拿到access_token可以生成签名
后端这里给出egg.js写出的代码:

// 判断ticket值从哪里获取
  async getAccessTicket() {
    const { app } = this;
    const ticket = await app.redis.get('ticket');
    // redis 存在ticket
    console.log(ticket, 'ticket');

    if (!ticket) {
      const res = await this.getTicket();
      return res;
    }
    // redis 存在ticket
    return ticket;
  }

  // 获取ticket 定时任务
  async getTicket() {
    const { ctx, app } = this;
    const access_token = await this.fetchAccessToken();
    console.log(access_token, '换key');
    const res = await ctx.curl(
      `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`,
      {
        // 必须指定 method
        method: 'GET',
        dataType: 'json',
      }
    );
    console.log(res, 'ticket_response');
    if (res.data.ticket) {
      await app.redis.set('ticket', res.data.ticket);
      return res.data.ticket;
    }
    return null;
  }
  1. JS-SDK
yarn add weixin-js-sdk

5.1 公众号设置-功能设置
5.1.1 js接口安全域名配置
代码所在的服务器配置访问页面的url,例如:
访问页面地址如下:
http://gzh-test.nangaoyun.com/quality/#/welcome

那 js接口安全域名配置:http://gzh-test.nangaoyun.com/quality
需要把MP_verify_dPqSolp0G3VuCs9n.txt放在服务器http://gzh-test.nangaoyun.com/quality指向的文件夹下

访问页面地址如下:
http://gzh-test.nangaoyun.com/plan/#/welcome

那 js接口安全域名配置:http://gzh-test.nangaoyun.com/plan
需要把MP_verify_dPqSolp0G3VuCs9n.txt放在服务器http://gzh-test.nangaoyun.com/plan指向的文件夹下

以上我们看到访问地址在服务器的配置在同一个根目录下
因此可以只配置一个js接口安全域名:http://gzh-test.nangaoyun.com
需要把MP_verify_dPqSolp0G3VuCs9n.txt放在服务器http://gzh-test.nangaoyun.com/quality指向的文件夹下
//和http://gzh-test.nangaoyun.com/plan指向的文件夹下共同的根目录下面即可;

例如目录结构是这样的:
在这里插入图片描述

5.2 调用微信的一些功能,以下以扫码为例(前端代码)

//写一个公共方法:wxConfig

import { doFetch } from "./doFetch";
import { Toast } from "antd-mobile";
import wx from 'weixin-js-sdk';
export default async function (url) {
    let res = await doFetch({ url: '/pengli-wx/equip/common/jsSdk', params: { locUrl: url } });
    if (res?.code === 1) {
        let wxconfig = res?.jsSdk ?? {}
        wx.config({
            debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: wxconfig?.appId, // 必填,公众号的唯一标识
            timestamp: wxconfig?.timeStamp, // 必填,生成签名的时间戳
            nonceStr: wxconfig?.nonceStr, // 必填,生成签名的随机串
            signature: wxconfig?.signature,// 必填,签名
            jsApiList: [
                'scanQRCode'
            ] // 必填,需要使用的JS接口列表
        });
        wx.ready(function () {
            Toast.show({
                icon: 'success',
                content: '成功',
            })
        });

        wx.error(function (res) {
            Toast.show({
                icon: 'error',
                content: res.errMsg,
            })
        });
    }
}

按钮点击扫码:

async() => {
            await wxConfig(document.URL)
            wx.scanQRCode({
                needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
                scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
                success: function (res) {
                    var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
                }
            });
        }

**

PS: access_token和签名都是2小时过期

**
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
公众号前端发布,通过nginx部署到服务器,跟pc端页面部署一样
前端调试:微信开发者工具

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值