React-微信网页开发总结

前段时间用React写了几个微信公众号的网页,遇到的主要阻力就是微信的网页授权问题和JS-SDK使用问题。

1. 网页授权

根据微信官方网页授权介绍,只有在需要获取用户信息时,才需要用到微信网页授权机制。关于如何进行网页授权,官方文档已经介绍很详细了,这里主要记录一下使用过程中遇到的问题以及需要注意的地方。

1.1 网页授权access_token

由于一个公众号的网页授权access_token是所有人共用的,如果每个需要用到授权的服务都自己调用微信提供的获取access_token的接口,每调用一次都会刷新一遍access_token,之前的access_token将会过期,access_token也就无法实现缓存。而access_token默认是2小时内有效的,所以在开发时,需要有一个统一的授权中心,授权中心负责access_token的获取缓存和更新。
统一授权还有一个好处:在开发时,公众号上面的不同菜单的网页可能是部署在不同的服务器,但是公众号后台的网页授权域名设置只能设置一个,用统一授权就可以解决这个问题。网页授权域名设置为授权中心的域名,腾讯后台的回调都会回调到授权中心,由授权中心转发重定向回每个菜单的页面。

1.2 回调

调用授权接口时,要求传入一个回调地址redirect_uri。这个redirect_uri的域名必须要和公众号平台-设置-公众号设置-功能设置-网页授权域名一致。

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

回调网页还要一个需要注意的地方:如果调用授权的页面和配置的redirect_uri是同一个页面,会出现从redirect_uri页面后退时,又重新进入到调用授权页,导致无法退出的问题。

这个问题可以通过监听popstate,如果返回到了授权页,则直接调用wx.closeWindow();退出来解决。

    window.addEventListener("popstate", function(e) {
        console.log("test"); 
        var documentUrl = document.location.href;
        console.log("documentUrl=" + documentUrl );
        if (documentUrl.indexOf("weixin.qq.com") !== -1) {
          wx.closeWindow();
        } 
      }.bind(this));

2. 微信JS-SDK

微信JS-SDK说明文档里介绍的引入js-sdk的方式是在script标签里引入http://res.wx.qq.com/open/js/jweixin-1.4.0.js。这种方式在react上并不合适。

2.1 React集成JS-SDK

React上集成的方式和文档介绍的方式只有引入方式不一样,react需要先安装weixin-js-sdk的依赖包,再import。

  1. 在项目目录下执行
npm install weixin-js-sdk
  1. 在需要使用js-sdk的页面引入sdk
import wx from 'weixin-js-sdk';
  1. 之后的步骤和文档介绍的就一样了。
    附上完整的代码
import React from 'react';
import './DeviceList.css';
import Device from './Device';
import DeviceIcon from '../images/device_icon.png';
import ReactList from 'react-list';
import wx from 'weixin-js-sdk';
import InfiniteScroll from 'react-infinite-scroller';

const baseUrl = process.env.PUBLIC_URL;
const serverIp = process.env.REACT_APP_SERVER_IP;
const resourceServerIp = process.env.REACT_APP_RESOURCE_SERVER_IP;
const wxAppId = process.env.REACT_APP_WX_APPID;

const jsAuthAddress = process.env.REACT_APP_WX_JS_AUTH_ADDRESS;

export default class DeviceList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      tracks: [],
      hasMoreItems: true,
      nextHref: null,
      latitude:-1,
      longitude:0
    };
  }

  componentWillMount() {
    this.fetchSignatureAndLocation();
  }

  componentDidMount() {
    
  }

    loadItems(page) {
      var that = this;
      var url = serverIp + '/devices/' + this.state.longitude + '/' + this.state.latitude + '/'+ page;
      if (this.state.nextHref) {
        url = this.state.nextHref;
      }
      fetch(url)
        .then((res) => res.json())
        .then((responseJson) => {
          if (responseJson.flag == "00") {
            var tracks = that.state.tracks;
            responseJson.data.list.map((track) => {
              tracks.push(track);
            });
            if (responseJson.data.hasNextPage) {
              that.setState({
                tracks: tracks,
                nextHref: serverIp + '/devices/' + this.state.longitude + '/' + this.state.latitude + '/' + responseJson.data.nextPage
              });
            } else {
              that.setState({
                hasMoreItems: false
              });
            }
          } else {
            alert(responseJson.message);
          }


      }); 
  }

  checkJSApi() {
      wx.checkJsApi({
          jsApiList: [
               'getLocation'
            ],
            success: function (res) {
                console.log('wx check js api',res);
                if (res.checkResult.getLocation === false) {
                    alert('你的微信版本太低,不支持微信JS接口,请升级到最新的微信版本!');
                    return;
                }
            }
      });
}

  fetchSignatureAndLocation() {
    var that = this;
    var url = jsAuthAddress +'?appid='+ wxAppId + '&url=' + resourceServerIp + baseUrl + "/";//统一授权中心
    fetch(url)
    .then((res) => res.json())
    .then((responseJson) => {
          console.log(responseJson.message)
          wx.config({
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: wxAppId, // 必填,公众号的唯一标识
            timestamp: responseJson.timestamp, // 必填,生成签名的时间戳
            nonceStr: responseJson.noncestr, // 必填,生成签名的随机串
            signature: responseJson.signature,// 必填,签名
            jsApiList: [       
              'checkJsApi',
              'openLocation',
              'getLocation'
              ] // 必填,需要使用的JS接口列表
          });
          wx.ready(function () {
              console.log('wx config ready');
              //基础接口判断当前客户端版本是否支持指定JS接口
              wx.getLocation({
                type : 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
                success : function(res) {
                    
                    // alert(JSON.stringify(res));
                    var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
                    // $("#latitude").val(latitude);
                    var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
                    // $("#longitude").val(longitude);
                    var speed = res.speed; // 速度,以米/每秒计
                    // $("#speed").val(speed);
                    var accuracy = res.accuracy; // 位置精度
                    // $("#accuracy").val(accuracy);
                    that.setState({
                      longitude: res.longitude,
                      latitude: res.latitude
                    })
                },
                cancel : function(res) {
                    alert('用户拒绝授权获取地理位置');
                }
            });
          });
          wx.error(function(res){
            console.log('wx error', res);
             alert('wx config error');
               // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
          });
        })
    .catch((error) => {
      console.error(error);
    });

  }

  renderItem(index, key) {
    var distanceStr = '距离您' + this.state.deviceList[index].distance;
    var metroStationDes = this.state.deviceList[index].metroLine + '-'+ this.state.deviceList[index].name 
    return ();
  }

  render() {
    const loader = 
Loading ...
; var items = []; let scrool; this.state.tracks.map((track, i) => { var distanceStr = '距离您' + track.distance; var metroStationDes = track.metroLine + '-'+ track.name; items.push(
); }); if (this.state.latitude != -1) { scrool =
{items}
} return (
{scrool}
) } }

2.2 授权

引入JS-SDK也是需要授权的,我们也可以做一个统一的授权中心。和网页授权不一样的是,即使有这个统一的授权中心,同一个公众号的使用了js-sdk的网页必须部署在同一个服务器下。因为js-sdk的不仅校验回调的域名,还会校验使用js-sdk的网页路径,只有调用腾讯的授权接口时传入的回调url和我们网页部署之后访问的url一致才能通过校验。

你可能感兴趣的:(前端知识整理)