最近接到需求,需要做一個簡單小程序管理自家的設備,但又想增加銷售渠道,故打算做個小程序並內嵌自家微信公眾號商城。
總結主要問題:
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;
}
}
},
完