跳至主要內容

通过code获取用户信息

chanchaw大约 3 分钟languagewechat

概述

微信服务号H5页面不可直接赋予后台服务器上的地址,要在后台服务(java服务)中 将真实的地址经过微信服务器转换,这个过程结束后地址后面会被拼接上code。在H5页面中是没有当前微信用户的 openid 的,后台服务要鉴别进行当前操作的是哪个用户,需要前端拿页面中的 code 请求后端,后端拿该 code 请求微信服务器获取对应的 openid。一个H5页面中的 code 只能使用一次,多次请求会得到所有属性都是空值的返回对象,所以这里就有坑了,如果后端 java 仅仅判断返回了对象就取其中的属性 openid ,就会出现空指针异常了。所以合理的使用方法是前端页面使用 code 直接请求 openid ,获得结果后缓存起来,当前页面的其他所有操作都不再请求 openid 直接使用即可。

实现

新东方的服务号和精之研的服务号都在 controller 中都有该接口

代码

前端请求 openid

下面是前端 js 代码,其中的函数 getUrlParam 是通过正则表达式获取指定名称的参数,另外一个函数 getOpenid 则是通过 code 获取 openid

function getUrlParam(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)","i");
    var r = window.location.search.substr(1).match(reg);
    if (r!=null) return (r[2]); return null;
}

function getOpenid(){
    var code = getUrlParam("code");

    let that = this;
    // 后端项目名称是 wxbe,对应控制器注解是 wechat
    // 具体请求是 getWxJsApiConfigs,其后跟随当前页面的URL
    const url = 'https://www.jzy.world/wxbe/wechat/openid/' + code ;
    $.ajax({
        type : "GET",
        contentType: "application/json;charset=UTF-8",
        url : url,
        success : function(res){// 返回的数据是配置对象构成的数组,取下标2
            alert(res.data)
        },
        error : function(e){//请求失败,包含具体的错误信息
            alert(e.status + ':' + e.responseText);
    }})
}

后端通过 code 请求 openid

package com.xdf.flux_trans.model;

/**
 * @ClassName:WebAuthorizeResult
 * @Description:使用 code 请求微信服务器获得 openid 时返回的对象模型
 * @Author:chanchaw
 * @Date:2019/10/13 15:17
 * @Version:1.0
 **/
public class WebAuthorizeResult {
    private String access_token;
    private String expires_in;
    private String  refresh_token;
    private String  openid;
    private String  scope;

    private int errcode;
    private String errmsg;

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(String expires_in) {
        this.expires_in = expires_in;
    }

    public String getRefresh_token() {
        return refresh_token;
    }

    public void setRefresh_token(String refresh_token) {
        this.refresh_token = refresh_token;
    }

    public String getOpenid() {
        return openid;
    }

    public void setOpenid(String openid) {
        this.openid = openid;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public int getErrcode() {
        return errcode;
    }

    public void setErrcode(int errcode) {
        this.errcode = errcode;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }

    @Override
    public String toString() {
        return "WebAuthorizeResult{" +
                "access_token='" + access_token + '\'' +
                ", expires_in='" + expires_in + '\'' +
                ", refresh_token='" + refresh_token + '\'' +
                ", openid='" + openid + '\'' +
                ", scope='" + scope + '\'' +
                ", errcode=" + errcode +
                ", errmsg='" + errmsg + '\'' +
                '}';
    }
}

// 使用前端传递来的 code 请求微信服务器获取对应的 openid
// 如果多次使用同一个 code 会导致返回的 openid 是 null ,这里要特别注意
public String getOpenidByOAuth(String code) throws IOException {
        String openidUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";
        String requestUrl = openidUrl.replace("APPID", DevMaterial.JZY.APPID).replace("APPSECRET", DevMaterial.JZY.APPSECRET).replace("CODE", code);

        String result = HttpUtils.sendGet(requestUrl);
        WebAuthorizeResult openidResult = mapper.readValue(result,WebAuthorizeResult.class);
        if( openidResult == null ){
            throw new BusinessException("使用code请求openid发送get请求后获得了空数据");
        }

        return openidResult.getOpenid();
}