记小程序内嵌商城踩过的坑

最近接到需求,需要做一个简单小程序管理自家的设备,但又想增加销售渠道,故打算做个小程序并内嵌自家微信公众号商城。

总结主要问题:

  1.小程序返回问题

  2.支付问题

  3.商城访问权限问题

  4.ssl证书问题

  5.端口号冲突问题

 

问题解决:

  1. 小程序返回问题

   问题详情:小程序利用<web-view>嵌入商城界面,左上角返回发现会先出现一次空白页,第二次才会回到小程序页面

     原因查找:进入商城时首先会有个微信授权页,然后才会进入微信商城,所以要返回两次

     问题处理:由于商城里面还有多个界面,所以不能采用网上流传的监控界面退出事件跳转小程序(不然进入商城子界面的时候也会直接退回小程序),此问题基本无解,但也不是什么影响功能的问题所以可以放宽要求。但是商城内部进入多个界面后,左上角的返回需要一层一层返回,十分不便严重影响用户体验,因此在商城里面的tab栏添加一直接返回小程序按钮,通过判断当前环境,如果是小程序环境下就显示改tab,否则隐藏。

   技术要点: 

<script type="text/javascript" src="${pageContext.request.contextPath}/UI/weixin/js/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
<script type="text/javascript">
    var ua = navigator.userAgent.toLowerCase();
    if(ua.match(/MicroMessenger/i)=="micromessenger") {
        wx.miniProgram.getEnv((res)=>{
            if (res.miniprogram) {
                //小程序环境
                $("#deviceXiao").show();
                $("#deviceH5").hide();
            }else {
        //微信环境
                $("#deviceH5").show();
                $("#deviceXiao").hide();
            }
        })
    }else {
//非微信环境
        $("#deviceH5").show();
        $("#deviceXiao").hide();
    }
    // alert(typeEnvironment);
    function xiao() {
        wx.miniProgram.navigateTo({ //这将唤起小程序的原生页面
            url: '/pages/index/index',
        })
    }
</script>    

    注意: 建议跳转小程序原生界面用wx.miniProgram.redirectTo,避免左上角放回键又放回网页。

wx.navigateTo保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。
wx.redirectTo关闭当前页面,跳转到应用内的某个页面。
wx.switchTab跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
wx.navigateBack关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages()) 获取当前的页面栈,决定需要返回几层。
wx.reLaunch关闭所有页面,打开到应用内的某个页面

//不同的跳转方式会导致不同的页面栈的变化从而会影响客户回退页面的顺序的,所以我们需要合理的使用不同的跳转方法。如果使用不当就会导致跳转混乱影响用户体验

 

 

  2.支付问题

   问题详情:当下单支付的时候发现微信支付唤不起。

     原因查找:小程序环境下不支持微信H5支付

     问题处理:在商城选择微信支付的时候判断当前环境,如果是小程序环境则跳转小程序新建页面进行支付,在该界面访问新的统一下单接口并唤起小程序支付(统一下单的appid和秘钥为小程序的),支付成功后跳转商城订单页面。

     技术要点:

//唤起小程序支付
 starpay:function(obj){
   var appid = wx.getAccountInfoSync().miniProgram.appId;
   var timeStamp = obj.timeStamp;
   var nonceStr = obj.nonceStr;
   var packages = obj.package;
   var signType = obj.signType;
   var paySign = obj.paySign;
   var orderid = obj.orderId;
   wx.requestPayment(
     {
       'timeStamp': timeStamp,
       'nonceStr': nonceStr,
       'package': packages,
       'signType': signType,
       'paySign': paySign,
       'success': function (res) { 
        //  接口调用成功的回调函数
         wx.showToast({
           title: "支付成功",
           icon: 'none'
         })
         wx.navigateTo({
           url: '../shop/shop?shopUrl=UI/order_pay_success.html&orderId=' + orderid
         })
       },
       'fail': function (res) {
        //  接口调用失败的回调函数
         wx.showToast({
           title: "支付取消",
           icon: 'none'
         })
        },
       'complete': function (res) { 
        // 接口调用结束的回调函数(调用成功、失败都会执行)
       }
     })

 },

 

  3. 商城访问权限问题

   问题详情:从小程序访问统一下单接口没有访问权限

   原因查找:请求头中没有存入会话信息

   问题处理:在跳转小程序支付页面时,将商城里session中存的cookis传到小程序中,再在统一下单时将其封装到请求头中。

   技术要点:

//商城后台
    Cookie[] cookies = this.getRequest().getCookies();
          //遍历所有的cookie,然后根据cookie的key值来获取value值
            if (cookies!=null) {
                String JSESSIONID="";
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals("JSESSIONID")) {
                          JSESSIONID = JSESSIONID+cookie.getValue();
                        this.getRequest().setAttribute("JSESSIONID", JSESSIONID);
                        System.out.println(JSESSIONID);
                    }
                }
            }

 

//小程序 
onLoad: function (options) {
    this.setData({
      payPrice: options.payPrice,
      orderId: options.orderId,
      orderNum: options.orderNum,
      appid: wx.getAccountInfoSync().miniProgram.appId,
      cookies: options.cookies,
    })

 

  WXPay:function(){
  var that = this;
  //小程序内调用登录接口,获取到用户的code,便于商城后台根据code获取oppenid
  wx.login({
    success(res) {
      if (res.code) {
        console.log("res.code:" + res.code)
         //统一下单
        var fordata = {
          "type": "WEIXINXIAO",
          "openId": res.code,
          "orderId": that.data.orderId,
          "appid": that.data.appid,
          "payPrice": that.data.payPrice,
        }
        wx.request({
          url: `${rootUrl}UI/ajax_weixin_xiao_pay.html`,
          data: fordata,
          method: 'POST',
          header: {
            'content-type': 'application/x-www-form-urlencoded' ,// 默认值
            'cookie':"JSESSIONID="+ that.data.cookies,
           
          },
          success: function (res) {
            console.log('微信支付 ||' + res)
            wx.hideLoading();
            var resData = res.data;
            if (resData.code == "0") {
              var obj=resData.data;
              obj.orderId = that.data.orderId;
              console.log("orderId:"+obj.orderId);
              that.starpay(obj);

            } else {
              wx.showToast({
                title: "参数错误",
                icon: 'none'
              })

            }
          },
          fail: function (err) {
            wx.hideLoading();
            var errMsgStr = err.errMsg;
            if (errMsgStr == 'request:fail timeout') {
              errMsgStr = '设置超时,请连接设备后重试';
            }

            wx.showModal({
              title: '温馨提示',
              content: errMsgStr,
              showCancel: false
            })
          }
        })

      } else {
        console.log('登录失败!' + res.errMsg)
      }
    }
  })

  
},

 

//根据小程序code获取oppenid
    private static String Jscode2sessionUrl="https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";


/**
     * @param code jscode2session
     * @return
     */
    public static Map< String, Object > jscode2session( String code ,String appid,String secret) {
        logger.info( " begin jscode2session" );
        String requestUrl = Jscode2sessionUrl.replace( "APPID", appid ).replace( "SECRET", secret ).replace( "JSCODE", code );
        logger.info( " requestUrl={}", requestUrl );
        HttpClient client = null;
        Map< String, Object > result = new HashMap< String, Object >();
        try {
            client = new DefaultHttpClient();
            HttpGet httpget = new HttpGet( requestUrl );
            ResponseHandler< String > responseHandler = new BasicResponseHandler();
            String response = client.execute( httpget, responseHandler );
            JSONObject OpenidJSONO = JSONObject.parseObject( response );
            logger.info("OpenidJSONO:{}",OpenidJSONO.toString());
            String Openid = String.valueOf( OpenidJSONO.get( "openid" ) );
            String session_key = String.valueOf( OpenidJSONO.get( "session_key" ) );
            String unionid = String.valueOf( OpenidJSONO.get( "unionid" ) );//用户保存的作用域
            String errcode = String.valueOf( OpenidJSONO.get( "errcode" ) );
            String errmsg = String.valueOf( OpenidJSONO.get( "errmsg" ) );

            logger.info( " userinfo:openid={},session_key={},unionid={},errcode={},errmsg{}", Openid, session_key, unionid, errcode ,errmsg);

            result.put( "Openid", Openid );
            result.put( "AccessToken", session_key );
            result.put( "scope", unionid );
            result.put( "refresh_token", errcode );
        } catch ( Exception e ) {
            e.printStackTrace();
        } finally {
            client.getConnectionManager().shutdown();
        }
        logger.info( " end jscode2session" );
        return result;
    }

 

   4.ssl证书问题

    问题详情:小程序没问题了,但是从公众号进去小程序就一片空白。

    原因查找:公司原有的ssl协议过期了,进入网站时报风险,所以微信浏览器下就空白了,将链接复制到其他浏览器就会报风险提示。

    问题处理:在网上查找发现可以免费注册申请腾讯云的ssl协议

    技术要点:

server.ssl.key-store=/opt/uuwifi/sys/shop.xxx.net.jks
server.ssl.key-store-password=f8o1xxxxa938y
server.ssl.keyStoreType=JKS
#server.ssl.keyAlias=密码

 

  5.端口号冲突问题

   问题详情:点击商城进去报:redirect_uri 参数错误。

   原因查找:我们微信商城是公众号授权登录的,由于之前是http协议,默认的端口号是80,现在改成https协议,那么端口号就不能默认而要写出来了,而微信授权回调接口不支持端口号的填写。

   问题处理:将回调的url中的 :80 省略掉(此时默认就是443端口),然后在服务器配置,将443端口的访问转发到80端口。

   技术要点:

iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 80   

注:网上朋友的命令dport 前面都是 一个 -,通常都会报错。另外如果防火墙重新启动,该命令就会失效。可以使用下面的命令把该规则保存到iptables里面 : service iptables save

      (服务器配置非亲测可能有误差)

  取消

service iptables restart

 

    6.ios系统小程序时间显示bug处理

  问题详情:后台传过来的时间,在ios系统上显示NAN。

  问题处理:将字符串中的 '-' 先替换成 '/'  再进行时间转换  var invalidDate = new Date(lastPkg.invalidDate.replace(/-/g, '/'));

 

 7. udp 通信

    // udp 通信替换
    const udp = wx.createUDPSocket();
    udp.bind();
    indexThis.udp.send({
      address: '192.168.0.1',
      port: 8090,
      message: '{"msg":"GET","seq":4294967295}'
    })
    udp.onMessage(indexThis.onUdpMessage) //指定接收事件处理函数

 

  //UDP 接收到数据的事件处理函数,参数res={message,remoteInfo}
  onUdpMessage: function (res) {
   
    var indexThis=this;
    if (res.remoteInfo.size > 0) {
      console.log('onUdpMessage() 接收数据 ' + res.remoteInfo.size + ' 字节:' + JSON.stringify(res, null, '\t'))

      // 将 ArrayBuffer类型的res.message取出来
      let unit8Arr = new Uint8Array(res.message)
      let encodedString = String.fromCharCode.apply(null, unit8Arr)
      let decodedString = decodeURIComponent(escape((encodedString)))//没有这一步中文会乱码
      console.log('message:'+decodedString)
      // 将 ArrayBuffer类型的res.message取出来

           //成功则取消定时任务
           clearTimeout(indexThis.data.timerReqFail);
           var resData =  decodedString;
            
           if (resData != null) {
             var deviceData = JSON.parse(resData).data;
   
            }

       
    } 
      
  },

 

 

  

posted @ 2020-02-21 18:37  一个九  阅读(939)  评论(0编辑  收藏  举报