昨天生产系统上报出一个问题:用户做一次扫码交易,出现了两条交易记录。幸好支付渠道对支付码有限制只成功了一笔,没有出现多扣钱的问题。

现在我们要排查一下,为什么做一次操作会出现两条交易记录。

我们的后台服务是部署了双机,通过阿里云的SLB做负载。在部署服务的两台机器上分别查到了两次交易记录的日志。

一台机器 2021-12-14 13:56:30.100 收到请求,中间调用支付渠道服务耗时2秒,最终2021-12-14 13:56:33.023 返回结果。

另一台机器 2021-12-14 13:56:31.275 收到请求,调用支付渠道服务时报错,2021-12-14 13:56:31.908 返回结果。

后台服务分别收到了请求,现在要确认的是:是SLB转发了两次,还是客户端做了两次请求。

联系阿里云的人协助排查SLB的日志。最终在SLB上也找到了两次请求。两次请求的IP还不一样。一个是移动的一个是电信的。因为商户仅有一台智能POS机,不可能是同时用两台做扫码支付。

猜测是android或java的重发机制。在网络上确实查到有人遇到过类似的问题:Android或者Java发送Http自动重发请求的解决方案

    由于设置了链接与获取数据的超时时间,客户端在发送数据之后,检测到可能并没有发送成功到后端,这个时候http底层会自动重发请求(注意是Http底层,所以应用端不会知道发送了多次请求)。如果应用端自动重发了多次请求,后端也回复了多次请求,但是前段仅仅会只回复1次请求。所以为了解决这个问题,只要在DefaultHttpClient设置如下代码即可解决:

    defaultHttpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0,false));

于是,我们可以给出一个解释: 用户做扫码操作时,网络出现问题,智能POS从WiFi连接自动切换到了移动连接,此时客户端做了一次请求重发。

因为智能POS是android系统,我们部署在智能POS上的支付app是使用okhttp发起后端请求的,需要修改okhttp相关的代码来规避这个问题.

当然,网上也能找到遇到类似问题的人:实现OkHttp自定义重试次数 我们不需要自定义重试次数,我们要禁止重试。所以只需要在构建okhttpClient的时候加一句

    retryOnConnectionFailure(false)

至此,问题定位修改完成,待系统升级后继续观察。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: https://wangxuan.me/tech/2021/12/15/android-http-request-resend-bug-fix.html

android端http请求重发问题定位过程的更多相关文章

  1. 【Android端 APP GPU过度绘制】GPU过度绘制及优化

    一.Android端的卡顿 Android端APP在具体使用的过程中容易出现卡顿的情况,比如查看页面时出现一顿一顿的感受,切换tab之后响应很慢,或者具体滑动操作的时候也很慢. 二.卡顿的原因 卡顿的 ...

  2. Java服务器对外提供接口以及Android端向服务器请求数据

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5056780.html 讲解下java服务器是如何对移动终端提供接口的,以什么数据格式提供出去,移动端又是怎么 ...

  3. Android端百度地图API使用详解

    百度地图API简介 百度地图移动版API(Android)是一套基于Android设备的应用程序接口,通过该接口,可以轻松的访问百度服务和数据,构建功能丰富.交互性强的地图应用程序. 百度地图移动版A ...

  4. 【转载】Android端百度地图API使用详解

    转载地址:http://www.cnblogs.com/rocomp/p/4994110.html 百度地图API简介 百度地图移动版API(Android)是一套基于Android设备的应用程序接口 ...

  5. Android ListView分页载入(服务端+android端)Demo

    Android ListView分页载入功能 在实际开发中经经常使用到,是每一个开发人员必须掌握的内容,本Demo给出了服务端+Android端的两者的代码,并成功通过了測试. 服务端使用MyEcli ...

  6. Vue项目用于Ios和Android端开发

    起因 前公司商城App项目使用的是H5开发,有微信公众号.Ios和Android三个版本,H5版本是自己写的一套框架,已经用了有些年头了,承载不下不断涌现出的新需求.而Ios和Android端通过we ...

  7. Macaca初体验-Android端(Python)

    前言: Macaca 是一套面向用户端软件的测试解决方案,提供了自动化驱动,周边工具,集成方案.由阿里巴巴公司开源:http://macacajs.github.io/macaca/ 特点: 同时支持 ...

  8. 用.Net打造一个移动客户端(Android/IOS)的服务端框架NHM(四)——Android端Http访问类(转)

    本章目的 在上一章中,我们利用Hibernate Tools完成了Android Model层的建立,依赖Hibernate Tools的强大功能,自动生成了Model层.在本章,我们将继续我们的项目 ...

  9. ProtocolBuffer在Android端的解析

    开题篇 近期公司在使用Protocol Buffer替代原先的json作为移动端的数据交互格式.虽然服务端和CTO把这项新技术吹的天花乱坠,说什么体积小,不易被破解乱七八糟的.可是作为Android端 ...

  10. 如何做好 Android 端音视频测试?

    在用户眼中,优秀的音视频产品应该具有清晰.低延时.流畅.秒开.抗丢包.高音效等特征.为了满足用户以上要求,网易云信的工程师通过自建源站,在SDK端为了适应网络优化进行QoS优化,对视频编码器进行优化, ...

随机推荐

  1. 低成本FPGA的MIPI测试GOWIN和LATTICE CROSSLINK

    本次实验MIPI屏,2.0寸,分辨率是240*320 RGB888, 接口如下: 接上IO就是RST和MIPI的时钟和数据接口,另外就是电源和地. 一:GOWIN的测试方案 Gowin的案例中,首先是 ...

  2. easyx的使用,图像插入(2.0)

    本文从B站学习,借鉴,一些贴图素材借鉴游戏网图: 视频链接:图像输出_哔哩哔哩_bilibili 想使用图片,先用easyx提供的数据类型定义一个变量: 在对图片进行加载,差不多像是赋值,这个变量名相 ...

  3. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-39-highlight() 方法之追踪定位

    1.简介 在之前的文章中宏哥讲解和分享了,为了看清自动化测试的步骤,通过JavaScript添加高亮颜色,就可以清楚的看到执行步骤了.在学习和实践Playwright的过程中,偶然发现了使用Playw ...

  4. Timing:在线自习室快速搭建

    ​通过超低延迟的音视频通信技术.视频连麦.弱网传输算法,快速搭建自习场景,提升自习效率. 客户简介 ​ 氪细胞主打产品Timing,是国内最早推出,也是规模最大的在线自习室,是新一代的教育与社交融合平 ...

  5. 自建Kubernetes集群如何使用弹性容器实例ECI

    简介: 虚拟节点(Virtual Node)实现了Kubernetes与弹性容器实例ECI的无缝连接,让Kubernetes集群轻松获得极大的弹性能力,而不必受限于集群的节点计算容量.您可以灵活动态的 ...

  6. dotnet 使用 NamedPipeClientStream 连接一个不存在管道服务名将不断空跑 CPU 资源

    本文记录一个开发和代码审查过程中,需要关注的细节.在 dotnet 里,在 .NET 6 和以下版本,包括 .NET Framework 版本,使用 NamedPipeClientStream 进行连 ...

  7. PostMan测试图片上传接口的方法

    一.选择POST后添加接口地址 二.选择Body下的from-data 注:Headers不要加参数 三.填写key,再key后的下拉选择file,然后选择文件 注:key并不是图片名称,而是接口接收 ...

  8. LLM生态下爬虫程序的现状与未来

    最近出现一批与LLM有关的新的爬虫框架,一类是为LLM提供内容抓取解析的,比如 Jina Reader 和 FireCrawl ,可以将抓取的网页解析为markdown这样的对LLM友好的内容,例如m ...

  9. ContextCapture中的模型航拍方法和技巧

    在进行实景建模之前,获取被拍摄物体的照片是很重要的一项工作,因为如果没有按照规则拍摄或者拍摄相片质量不佳,将会直接影响我们后期建模,甚至无法建模. 我们建议使用ContextCapture进行建模,则 ...

  10. jeecg-boot中分页接口用自定义sql和实体实现

    1.controller实现 @RequestMapping(value = "/list", method = RequestMethod.GET) public Result& ...