微信小程序

微信小程序服务端踩坑记录,不定期更新中

2017-11-22  本文已影响457人  zzqiltw

微信小程序踩坑记录,不定期更新中

Alt pic

【超硬小广告,大家可以关注一下我们美学福利社的小程序,我们会不定期推出明星单品试用。免费的噢。】

目前网易美学上线美学福利社小程序,是一个单独的消费工程。由于小程序是在微信容器中运行,诸多特性和API需要遵循微信的规范和标准。虽然微信正在不断努力地开放功能,完善标准,然而就现阶段而言,一些没有在文档中提到的要点仍然困扰着开发者。
本次微信小程序的开发,是一个痛苦的踩坑、摸索、完善的过程。现在把一些开发过程中遇到的注意点记录下来,希望能帮助到遇到同样问题的朋友们。

参考文档

  1. 小程序官方文档:https://mp.weixin.qq.com/debug/wxadoc/dev/index.html
  2. 微信公众平台开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432

openid & unionid

openid和unionid都作为微信用户身份凭证,可以用于区分用户。但是,在早些时候App端接入OAuth2做三方登录时,由于Android和iOS的openid不一致,导致两个操作系统的用户无法判别。所以需要识别用户身份或者要求唯一性的情况下,请使用unionid。
并且,在OAuth2拿到的openid和在小程序中拿到的openid会不一致,在发送模板消息的时候需要填入openid做参数,请使用小程序中的openid。
官方解释如下:

Alt pic

wx.getUserInfo(OBJECT)

前端获取用户信息的接口,如下官方所示

Alt pic

当用户是新微信并且没有关注过小程序关联的公众号or服务号时,该方法获取到的openid可能为null。
比较保险地获取openid和unionid的方法应该是拿到encryptedData,用iv做解密,然后反序列化拿到openid。
官方文档如下:


Alt pic
Alt pic

官方的解密demo示例宣称覆盖多种主流服务端开发语言,但是并没有提供Java版本,果然是有程序语言鄙视链存在。PHP是世界上最好的语言。


Alt pic

Java解密主要代码如下:


public class AESUtils {
    public static boolean initialized = false;
    /**
     * AES解密
     * @param content 密文
     * @return
     */
    public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws Exception {
        initialize();
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(keyByte, "AES");
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    public static void initialize(){
        if (initialized) return;
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }
    //生成iv
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception{
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }
}


Cookies

微信小程序不支持Cookie,但是支持request、response header,所以可以借用header来模拟Cookie机制。
response中设置“Set-Cookie”的header,request中再带上“Cookie”,再手动做解析、过期时间来处理就可以了。
虽然功能能实现,但是毕竟有些繁琐。


Template Message

模板消息,就是在微信用户关注了对应的服务号后,微信的会话列表会出现一个服务消息的会话栏,里面可以保存开发者向用户推送的消息。
下面是官方描述:

基于微信的通知渠道,我们为开发者提供了可以高效触达用户的模板消息能力,以便实现服务的闭环并提供更佳的体验。

模板推送位置:服务通知

模板下发条件:用户本人在微信体系内与页面有交互行为后触发,详见下发条件说明

模板跳转能力:点击查看详情仅能跳转下发模板的该帐号的各个页面

要想发送模板消息,首先得有模板。
创建模板的方式有两种
一种是人工在微信公众平台填写信息创建模板。
第二种是通过开发API去创建。

创建好模板后,准备发送模板消息。
首先要获取access_token,作为小程序全局唯一接口调用凭证,有效期2个小时。


Alt pic

简单存redis中。

    @Override
    public String getWxaAccessToken() throws Exception {
        String key = "access_token";
        String access_token = redisService.get(key);

        if (StringUtils.isEmpty(access_token)) {
            WXAccessTokenRequest request = new WXAccessTokenRequest();
            WXAccessTokenResponse response = request.sendRequest();
            if (StringUtils.isNotEmpty(response.getAccess_token())) {
                redisService.setWithExpireTime(key, response.getAccess_token(), response.getExpires_in());
            }

            access_token = response.getAccess_token();
        }
        return access_token;

    }

然后向微信的服务器POST一条请求就可以发送模板消息。

Alt pic

有一些参数需要说明一下。

  1. 如果你调试模板消息发现虽然收到模板消息,但是数据是空的,那么请检查你的data参数是一个JSONObject而不是一个String。
  2. form_id是由用户本人在微信体系内与页面有交互行为后触发,具体到代码中,是前端使用<form>组件,在formSubmit函数中获取form_id。form_id和openid是多对一的关系。只有由openid和小程序交互产生的form_id才能用于发送模板消息。
  3. form_id据微信的说法,有效期大概是7天,微信不保证。

看到这里,微信的想法应该是在于小程序交互时给用户发送提醒,微信并不希望模板消息用在主动给用户推送消息造成打扰。

那么,假如策划的需求是,在其他的运营后台系统(非微信)点击按钮(比如抽奖通知)想要通知用户,达到一个主动push的功能,该如何完成呢?
我们利用form_id有效期7天,可以做一些事情。我们把前端大部分的组件都包装成<form>,用户每次点击,收集一个openid、form_id的mapper,存入redis中,并将openid存入用户数据库。在运营想给用户推送一些数据时,查到所有的openid,顺便找到form_id,然后从form_id中找到一个最老的并且没有过期的id,发送模板消息并移出redis。

Alt pic

Java部分代码如下:

    @Override
    public ControllerResult<Void> gatherFormId(String form_id, long currentTime, String openid) {
        LOGGER.info("WXATokenFacadeImpl#gatherFormId: {} openid : {}", form_id, openid);

        if (StringUtils.isEmpty(openid)) {

            return ControllerResult.fail(BeautyCode.SYS_ERROR, "openid为空,自动舍弃form_id");

        }

        String key = RedisKeyGenerator.keyForOpenIdFormIdMapper(openid);

        redisService.zadd(key, Double.valueOf(currentTime), form_id);

        return ControllerResult.ok(null);
    }

    @Override
    public String findOldestFormIdAndRemove(String openid) {
        if (StringUtils.isEmpty(openid)) {
            LOGGER.info("WXATokenFacadeImpl#findOldestFormIdAndRemove:openid : {}", openid);
            return null;
        }

        long currentTime = System.currentTimeMillis();
        long lastestTime = currentTime - EXPIRE_TIME_MS - 1;// 比这个时间大才有效

        String key = RedisKeyGenerator.keyForOpenIdFormIdMapper(openid);

        redisService.zremrangebyscore(key, 0, lastestTime);

        List<String> formIds = redisService.zrangebyscore(key, lastestTime, currentTime, 0, 1);
        if (CollectionUtils.isNotEmpty(formIds)) {
            String formId = formIds.get(0);

            // 删除formid
            if (StringUtils.isNotEmpty(formId)) {
                redisService.zrem(key, formId);
            }

            return formId;
        }

        return null;
    }

本文不定期更新~

超硬小广告:最后欢迎大家关注“美学福利社”,有很多好用的明星单品可以免费申领试用噢!!


Alt pic
上一篇 下一篇

猜你喜欢

热点阅读