React-微信网页开发总结

本文总结了使用React进行微信网页开发时遇到的授权问题和JS-SDK集成经验。包括网页授权的access_token获取与缓存、回调处理,以及在React中集成微信JS-SDK的方法和授权注意事项。

前段时间用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 (<Device deviceDistance={distanceStr} deviceName={metroStationDes}   imageURL={DeviceIcon}></Device>);
  }

  render() {
    const loader = <div className="loader">Loading ...</div>;
    var items = [];
    let scrool;
    this.state.tracks.map((track, i) => {
      var distanceStr = '距离您' + track.distance;
      var metroStationDes = track.metroLine + '-'+ track.name;
      items.push(
          <div className="track" key={i}>
              <Device deviceDistance={distanceStr} 
              deviceName={metroStationDes}
              imageURL={DeviceIcon}></Device>
          </div>
            );
        });
    if (this.state.latitude != -1) {
      scrool = <InfiniteScroll
                pageStart={0}
                loadMore={this.loadItems.bind(this)}
                hasMore={this.state.hasMoreItems}
                loader={loader}>

                <div className="tracks">
                    {items}
                </div>
            </InfiniteScroll>
    }

return (
			<div class="DeviceListContainer">
        		<div class="DeviceListView">
         			 {scrool}
       			 </div>
       		</div>
			)
	}
}

2.2 授权

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值