第一种:其他浏览器呼起微信支付。
第二种:微信内部呼起微信支付。
我这边的项目要求的两种方式均要适用。 产品要求是当支付失败时或者未支付情况是停留在支付订单页面,可再次发起订单请求(新订单),故我在这项目中,把支付成功页面和订单页面在同一页(根据订单状态去展示)。
内部呼起微信搭桥,需要配置一个网页授权域名,用于前端内部呼起微信生成对应的code给到后端。
需要注意的是,填入域名即可,不用在域名前加【http://】,不然会提示【域名或路径格式不正确,请参考注意事项】。别问我怎么知道的,因为我删掉了我写的前面【http://】就配置通过了。
后端涉及到支付,要配置支付授权。
公众平台配置位置:微信支付-开发设置-支付授权目录

初始化时判断浏览器内核,并针对不同情况做不同的事情。
init(){
this.wechatFlag = this.isWeChat();//本人项目提交时需要判断区分,所以就定义了全局
if(this.wechatFlag){
//当前在微信内部 do someThing
// 比方判断是否有授权code
let code = this.getQueryObject().code;
if (code == null || code == '') {
this.redirectPage();//重定向获取code
} else {
this.code = code;
}
}else{
//外部浏览器 do someThing
//项目里,我设置的支付订单页和成功页在同一个页面
//所以外部浏览器付费与否都回到这个页面
//所以我这要获取成功后的订单参数
if (this.$route.query.orderNumber) {//外部浏览器跳转重定向
//从微信里重定向回来
this.orderId = this.$route.query.orderNumber;//订单参数
//this.getMyOrder();//请求订单数据
}
}
}
isWeChat(){
//判断是否为微信内部登录
var ua = window.navigator.userAgent.toLowerCase();
//console.log(ua);
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
return true;//是微信内部
} else {
return false;
}
}
}
getQueryObject(url){可当成一个公用方法
url = url == null ? window.location.href : url;
let search = url.substring(url.lastIndexOf("?") + 1);
let obj = {};
let reg = /([^?&=]+)=([^?&=]*)/g;
search.replace(reg, function (rs, $1, $2) {
let name = decodeURIComponent($1);
let val = decodeURIComponent($2);
val = String(val);
obj[name] = val;
return rs;
});
return obj;
}
思路:其他浏览器呼起微信支付,更多的是依靠后台接口返回数据。
请求微信支付的接口 --> 接口返回一个链接 --> 跳转连接
async submitOrder(){
this.isDisabledSubmitBtn = true //防止用户点击多次
let params= {};//项目支付相关的参数
try {
let {
retBody,
retMsg
} = await requestPay (params)//请求接口
if (retStatus === 'success') {//成功判断依据
if (retBody) {//直接跳转链接
window.location.href = retBody;
}
} else {
this.$notify(retMsg || '提交订单失败')
this.isDisabledSubmitBtn = false //防止用户点击多次
}
} catch (error) {
this.error = true
this.$notify('提交订单失败' || error)
this.isDisabledSubmitBtn = false //防止用户点击多次
}
}
}
跳转回来之后就在会重新create了,获取与后台约定参数重新查询订单数据即可。
需要前端搭桥呼起浏览器内置方法
redirectPage(){
//微信内部则重定向页面
let local = window.location.href;//当前地址
let appId = 'thisistheappid';//填写公众号APPID
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURIComponent(local)}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect` //跳转授权链接
},
submitOrderInside(){
let params = {
code:this.code,
};//微信内部添加的订单,后台需要我传多一个用户code
//因为code有时效性,所以失效了或者使用过之后需要重新获取个新的code
try {
let {
retStatus,
retBody,
retMsg
} = await requestPayInside(params)//支付接口
if (retStatus === 'success') {
this.orderId = retBody.orderNumber;
this.weChatParameter = {//微信搭桥需要的数据
appid: retBody.appid,
timeStamp: retBody.timeStamp,
nonceStr: retBody.nonceStr,
packageValue: retBody.packageValue,
signType: retBody.signType,
paySign: retBody.paySign,
};
this.wechatPay();//微信内置对象判断
} else {
this.$notify(retMsg || '提交订单失败')
this.isDisabledSubmitBtn = false //防止用户点击多次
this.redirectPage();//重定向获取新的code
}
} catch (error) {
this.error = true
this.$notify('提交订单失败' || error)
this.isDisabledSubmitBtn = false //防止用户点击多次
this.redirectPage();//重定向获取新的code
}
}
//搭桥前先解决微信内置对象报错
weixinPay (params) {
var that = this;
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', that.onBridgeReady(params), false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', that.onBridgeReady(params));
document.attachEvent('onWeixinJSBridgeReady', that.onBridgeReady(params));
}
} else {
that.onBridgeReady();
}
},
//微信内置浏览器类
onBridgeReady () {
var that = this;
var timestamp = Math.round(that.weChatParameter.timeStamp).toString();
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
debug: false,
"appId": that.weChatParameter.appid, //公众号名称,由商户传入
"timeStamp": timestamp, //时间戳,自1970年以来的秒数
"nonceStr": that.weChatParameter.nonceStr, //随机串
"package": that.weChatParameter.packageValue,
"signType": that.weChatParameter.signType, //微信签名方式:
"paySign": that.weChatParameter.paySign, //微信签名
jsApiList: [
'chooseWXPay'
]
},
function (res) {
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
if (res.err_msg == "get_brand_wcpay_request:ok") { //支付成功后的操作
that.isDisabledSubmitBtn = true;
//支付成功
that.getMyOrder();//请求成功后重新请求订单数据
} else if (res.err_msg == 'get_brand_wcpay_request:cancel') { //取消支付的操作
that.isDisabledSubmitBtn = false //按钮恢复高亮
that.redirectPage();//重定向获取新的code
//取消支付
} else {
//支付失败
that.isDisabledSubmitBtn = false //按钮恢复高亮
that.redirectPage();//重定向获取新的code
}
}
);
}
以上就是个人微信支付的思路以及部分代码。仅供参考。
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
我需要使用ActiveMerchant库在我们的一个Rails应用程序中设置支付解决方案。尽管这个问题非常主观,但人们对主要网关(BrainTree、Authorize.net等)的体验如何?它必须:处理定期付款。有能力记入个人帐户。能够取消付款。有办法存储用户的付款详细信息(例如Authotize.netsCIM)。干杯 最佳答案 ActiveMerchant很棒,但在过去一年左右的时间里,我在使用它时发现了一些问题。首先,虽然某些网关可能会得到“支持”——但并非所有功能都包含在内。查看功能矩阵以确保完全支持您选择的网关-http
参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin