1. 开发小参考
宗旨: 使用合适的方法和思路,在适合的条件下,在合适的时间内,解决适合的问题。不定规则,只做思想和操作的分享和参考,技术无止境也无必然,不同条件下不同阶段不同时间有不同的方法或思想,正确前行只是路标,具体怎么走得先看你自己准备怎么走。
- 不建议在代码中使用字符串拼接的方式来拼接一个 传入参数为字符串 的json串. 一旦传入的字符串有双引号,实际导致这个字符串已经不是一个Json字符串, 导致使用方解析错误. 可以使用Map或定义对象后做json转义处理.
不建议:"{\"str\":\""+str+"\"}" 参考:JSONObject.toJSONString(obj);
-
不要将你公网可以访问的处理数据ApiUrl经过qq消息的方式发给对方。qq常常会默认执行一次访问检测, 导致出现了异常执行. 要发请只发Api相对路径地址。(ip溯源可以看到是腾讯机房)
-
拼接字符串时, 使用a + b + c...的时候要注意,如果其中有两个值是数字类型,该用append, String.valueOf()时不要吝啬你的代码. 小心结果应该是12c变成了3c
-
数字计算如果是浮点数, 一定要注意精度丢失使用高精度计算. 切记不要几个个地方都写了, 最后一个地方漏了, 导致功亏于溃. 如果涉及到用户积分金额等数字, 建议在数据库涉及时直接使用整形存储, 比如最小单位1分钱. 1元就是 存储100. 可以很大程度上规避该问题.
-
前后端api交互所有时间尽量都保持使用时间戳或者统一格式交互. 可以很大程度避免各种时间转换错误, 以及不必要的格式化验证和处理. 包括前端时间查询条件的准确性:2019-01-01 00:00:59 ~ 2019-01-01 23:59:59看起来很完美, 但是当你数据库时间单位是毫秒的时候. 23:59:59.001~999 的数据均丢失, 而使用时间戳1546358399999不论是秒还是毫秒均不需要考虑该问题. (具体使用秒or毫秒根据业务需要来)
-
分页数据查询约定业务最大pageSize后, 后端必须做强校验, 防止无限制恶意拉取海量数据. 且分页查询为了避免数据增量, 应该在第一页查询后锁定lastId. 包括时间范围条件, 看起来每次 time<当天结束 没什么问题, 其实每次真实数据都在变化. 应该以第一页的数据时间作为锁定, 本质也不需要每次count, 只需要第一页count, 除非数据为动态变化, 但是动态变化的数据往往也没那么意这些细节. (也可以使用服务器当前真实时间). 更推荐lastId,这样每次只需要 where id < xx limit 10,而不需要 limit n,m , 越到后页性能越低. 而id模式性能更稳定也更优. (可扩展了解全局唯一id算法,天然集成时间特性, 再次减少大量数据下首次无id的性能损耗)
-
对象布尔类型属性命名不要使用is, 比如isVip, 直接用vip即可. 否则有的序列化工具会出现错误. 方法也是isVip. 他就认为是vip字段了, 无法匹配.
-
Integer 等整形包装类对象不能直接比较 Integer a == Integer b, 要么用intValue要么用equals (源码也是intValue).
-
大部分的数据查询以及查询后执行该对象的getXXX进行逻辑处理时,都该提前判断 obj !=null 或者 obj == null做友好处理, 不要让代码在中途异常错误. 包括大部分业务传入参数都应该做基本验证, 抛出更友好的异常提示信息. 而不是全部都是“未知异常”. 而本身数据为null有可能需要执行默认数据处理的也忽略了
-
数据查询中,如果已经查询到第一级数据为null或者count=0,则没有必要再进行后面的操作, 建议直接return. 关于return的值, 可以是null,没有强制说法需要返回空数组或默认值. 在某些业务下 没有设置和默认值完全是两个语义:比如age默认0和null.0本身就有含义0岁,用户如果没有设置,这里就不适合默认返回0,就该返回null。但是又比如是抽奖次数或余额这种默认0就可以让可读性更好, 代码注释说明清楚即可.
-
不论是创建线程, 线程池, db数据源, 缓存数据源. 都应该制指定有含义的名称name. 方便问题排查.
-
ThreadLocal 在定义线程局部变量时很方便, 但是切记使用完成后一定要remove();否则可能会导致后续业务异常复用.
-
不论是HttpClient、Lettuce、JedisPool、Druid都应该设置合理的超时时间。不要一概而论设置过长或者过短。业务接口可能往往3秒就足够了,但是一些数据处理的内部接口,设置过短导致没必要的timeout异常和补偿机制,一样业务接口如果都成为60秒那可能代价更高,不能快速释放导致资源快速消耗跑满。
-
对用操作用户资金积分等重要信息时, 应用层均可以加锁操作(uid或者uid+type为维度), 可以很大程度减少各种并发问题.如果应用层既没有操作锁,db层也没有唯一约束在分布式环境下这简直是灾难,分布式锁在分布式环境下的核心业务中能派上很大用处
-
不要只是因为网络不通程序就自动执行用户退款操作,退款必须获得明确的各方业务确认失败code后才能自动退款。同样也不能code是非成功就一改而论执行该操作,必须明确可退款错误码和非可退款错误码,突然识别的未知异常宁愿报警也不要自动退款,小心对方服务或网络故障,用户全部已到账但是你全给退款了,就是血的教学了。
-
生成二维码时, 二维码存放的信息只建议存放token等重要的标记信息, 业务间使用token获取具体数据, 不要将大量不必要的内容放入二维码中, 增加二维码复杂度和识别效率. 另外, 除非极端浏览器兼容需要下, 都该是后端提供二维码内容, 二维码由前端来生成, 不要让服务器做没有意义的存储或开销.
-
有时候做数据过期及验证时为了减少不必要的数据缓存或者存储,可以用aes等可逆数据加密做数据验证。比如扫码登录 每个用户有一个token,为了实现状态记录及N分钟过期,可能把token放入redis然后前端识别到token对应的状态变化,和用户做交互。这里就可以getToken 直接返回aes(uuid+time)。然后用户有状态变更需要记录时才需要真实写redis。既提升了性能,也减少了不必要的资源空间占用,而且还能防止恶意刷新token,反复数据写入。
-
不要认为所有日志均有必要打印, 大量无意义的info日志只会加大服务器开销, 并且对问题定位并没有多大的帮助. (比如数据上报, 处理时本身就有数据明细, 异常也有异常处理).
-
涉及用户个人资金及敏感数据, 都应该做数据归属验证(这条数据是否属于查询或使用者), 而不是直接靠各种ID或者orderId就可以查询到,甚至使用非本人数据. 如果使用token或uuid, 数据本身就有验证机制的可以酌情处理.
-
数据规则验证功能,后端应该在最终数据操作环节前再做一次完整验证,不要让用户有绕过的可能性,不要完全依靠前端的按钮或页面流程锁定来限制,这是前端之身的优化,可以拦住正常用户异常操作的可能性,但是后端数据要求的是最终拦截。特别是资金使用规则。比如优惠价满100减50,APP或者H5根据用户下单金额做了界面选择限制,如果后端不做最终验证的话,就算前端功能一直稳定也不能避免有人来恶意模拟接口使用。导致用户只花51就减50的话,这个锅必然是后端接。就算是前端代码突然异常导致限制没有生效,出现这种问题,也应该是后端清楚是自己的程序自我不够健壮严谨导致,前端关注的是更多的体验提升和细节、以及基础辅助,功能最终准确及安全性得靠后端自己
-
不要产品或者运营让你做用户数据批量修改或者自动给用户开打某个涉及用户个人资金的功能,特别是量大或者你自己都觉得有问题的时候,请整个项目组先讨论确实是否有法律风险,如果不能确认则反馈领导咨询法务后确认。开发者要有一定的法律意识,是对团队的保护也是对自己的保护。
-
涉及研发购买的付费服务或现金成本业务的功能(如发短信, 抽奖, 秒杀等). 都应该做单人及总量的上限预警, 上限预估(限制), 防重处理, 特别必要的时候增加验证码机制. 防止数量超限, 恶意刷量等.
-
使用购买付费组件时, 应该考虑一下是否有可能的组件成本降低方案. 不要所有数据每次都是直接裸裸的丢过去. 比如重复数据做结果复用, 短时间大量数据做数据聚合等.
-
后端开发业务时, 涉及前端轮询, 应该要和前端约定合理的轮询次数和过期机制, 并且协助验证是否正确. 某一天服务器流量突然飙高, 结果发现大量前端异常轮询请求. 等于是利用用户来ddos服务器.
-
前端上传的图片或面向用户的资源, 都应该和产品业务约定合理的大小限制. 如果是海量业务, 一个面向所有用户的首屏广告, 本来100kb, 变成了1mb. cdn费用直接飙升, 直接成为事故级别.
-
定时任务关注3个问题:1、防重复执行是否已处理. 2、处理耗时过长是否可以拿空间来换时间,空间大小是否合理,资源过大是否需要时间换空间(根据业务情况). 3、是否做了线上数据真实评估,合理拆分处理(每次处理上限), 及数据量异常告警.
-
为什么有的定时任务,做了告警还要建议做数据处理量分割,比如:现在一个任务处理用户数据需要使用付费服务,突然异常导致处理量暴涨,就算你告警了,但是等研发介入时可能已经把大量数据给处理完成了,钱已经没了。做数据合理分割,可以让你极大的避免数据量异常的场景。
-
大部分定时处理的任务都可以加数据补偿机制,特别是按天数据的数据,前日数据统计这一类。善用且正确的使用数据补偿机制会让你在线上业务运行中少些担心和操心。不论是何种触发器,是否有友好的中断机制,但是这都是触发器自身的健壮,程序也应该有自我的健壮和保护,不要过度依赖外部组件,别人挂了你 本可以 不挂也挂了,虽然锅可能是别人的,但是作为一个合格的开发者良心应该是过意不去的。
//举例比如某个业务要处理前日数据,最常见的处理流程是这样的 1、job每天0点XX分开始执行(+补偿时间点,或次日补偿) 2、执行方法 public void syncXXData(){ time = 今天-24H = 昨天 run time xxxxxxxx 开始业务逻辑处理昨天的数及写入 } //建议的流程如下,你会发现当你完整负责线上一条业务线的时候,操心的多了,相比上面这种你更喜欢用下面这种 处理流程 的方式。 public void syncXXData() { //第一步启用分布式锁(时间根据预估执行来) if (!redisLock.lock(lockKey, lockId, 1h)) { //xxxxxx忽略日志等代码 throw new BusinessLockedException(); } try { startTime = lastSuccessDay + 1 //如果没有查询到lastSuccessDay则使用默认初始化时间(比如max90Day) //有的查询做到了数据上次处理时间记录但是往往只是拿来作为失败证据,却没有做自我数据补偿,简单封装后,真正的代码没多几行 for { //按天执行处理 syncXXDataDo(day); //记忆本次处理成功的时间点 lastSuccessDay (如果被抛出异常则不会记录成功) } //日志耗时等成功处理 } catch (XXXXException e) { //告警,日志,异常处理等 alarm(xxx, e); } finally { redisLock.unLock(lockKey, lockId); } } //执行指定时间 public void syncXXDataDo(day){ //检测当天数据是否已执行过,已执行则直接return run day xxxxxxxx 开始业务逻辑处理指定时间的数据及写入 }
-
产品需求反复在细节上修改怎么应对, 清晰明白系统中可变设计和不可变设计的定位. 比如产品要求给用户发气球:开始1人1个红气球, 后面改为2个红气球, 然后再改3个蓝气球, 然后组合1个红2个蓝3个紫. 不要被产品带着走, 只需要明白这个系统就是, 给用户发物品(物品有类型, 颜色, 数量, 支持1对多即可, 考虑开发成本基本没有代价, 只要他没有完全推翻给用户发这个主流程, 这个应该是研发核心需要和产品做需求对接的内容, 确认不变和可变的, 以及开发性价比. )例子是死的, 拿到需求多分析和考虑才是合理的.
-
app开发初期注意提前预设置更新通道接口(强制,非强制,不是自更新), 而且优先级应该高且无干扰,app版本一旦下发, 没有提前做好各种预留处理, 会很难控制. 全靠后端临时补救, 只有靠异常而且App不一定识别.
-
app,后端,h5 大部分情况下本着这个顺序来设计维护性接口或体验性代码。app更新比后端代价高,后端更新比H5代价高。应用商店访问地址 或者 UI颜色管理方案,APP一个区域颜色产品有调整的可能性,这个后端就可以维护配置,而如果是h5就完全没必要后端额外维护,h5自行维护更新即可。
-
app及客户端版本号判断的时候,很多做法是一个verName1.0.0 一个 verCode100.然后后端就使用verCode 做版本大小判断。看起来没问题,但是实际这是费力不讨好的做法,导致版本每一位只能最大支持9否则就会计算错误,并且不符合各平台标准,比如2.0.1=201,1.0.11=1011 黑人问号???。请直接程序中使用verName转code后来做版本对比,按照3段999.999.999来计算2.0.1=2,000,001,1.0.11=1,000,011。推荐4段兼容大部分端的版本号。
-
如果查询数据有text等大型字段, 请明确区分列表概要查询和明细查询的时字段筛选, 不要为了方便总是select a,b,c,d from xxx
-
99%的表都应该有这3个字段:id主键,create_time,update_time. 可扩展is_deleted来标记是否逻辑删除, 不要做物理删除,也不要担心数据过多,大不了数据定期归档, 或者数据update. 都不要去直接删除数据.
-
mysql更多规范可以参考阿里文档,但是注意,mysql数据值查询是忽略大小写的,但是业务使用的时候特别是做md5或者aes时一定要注意是大小写敏感的,不要遗漏,该统一转换的记得统一转换,否则可能导致结果不一致。
-
mysql中有的表类型字段我们会用到tinyint,但是注意java中如果为tinyint(1),getObject时会被转为布尔类型. 所以往往直接使用tinyint(2)
-
没必要轻易在程序中使用事务,不是人人都能把事务玩的很6的,特别是分布式及多人协作开发下。并且像数据一致性这些有很多程序手段解决。只要源数据成功,那么后面的数据都有办法做的一致性处理,而源数据不成功本身也就拒绝用户了,不存在一致性问题。比如给用户完成任务,要做vip提升,任务加减积分或现金等一系列后续操作,这里本质上只要保证用户任务完成这一条源数据写入操作,后面的所有操作都可以程序补救,根本不需要引入事务。再比如写一条帖子,要更新类目计数器,个人计数器,索引查询表数据等,同理一个道理,只要源数据在程序就能回溯实现数据一致性。
-
sql中类型字段 多类型查询条件 sql不要写死在sql语句中, 统一配置由代码管理传入sql中. 比如123代表A业务, 456代表B业务, 789代表C业务. 应该统一提供getA,getB,getC的类型. 维护成本过大, 有改动难以保证全部更新. 和代码中避免魔法值是一个道理(if len>100 应该定义 maxLen =100, if len > maxLen).
-
如果产品设计用户文本输入可以支持表情内容,请记得选择utf8mb4进行存储。
-
大部分的开关功能,默认值或逻辑都应该关闭,而不是默认开启。数据丢失,查询异常,都应该是先让研发介入前,停止更多的数据异常进入,而不是反而被打开了。特别是下线功能,或一段时间关闭功能这种操作,因为很严肃的问题关闭了某个业务但是因为你做数据迁移,或数据很久淘汰了,结果默认就打开了,这个就不好开玩笑了。
-
redis虽好,但是使用一个你新用到的命令的时候核心关注下命令时间复杂度,当然也不要抗拒非O(1)的命令,在合理数据量控制下,能帮我们解决不少问题。比如SortedSet权重分割处理。总之正确使用高于 过于保守和过于激进图新。
-
redis的key命名建议按照业务或服务模块进行keyName前缀形式的命名空间隔离.前期数据量小方便共用,后期方便隔离和迁移,开发也更流畅。
-
使用redis做广告数据缓存的时候注意,有广告我们可能会按用户,商家,地区等维度设置广告数据。但是有时候任务检测到当前没有生效的广告就直接retrun了。这里注意需要做清理动作。hmset更好注意该问题,如果你每次处理因为只去读到了一部分子项有数据,就只更新了子项,但是没有数据的其他子项是需要做处理的,否则就存在怎么撤销下线广告没有生效的问题。
-
做geo计算用户周围的人或者商家时, 不论是用哪种geo算法工具, 都应该进行逻辑区域划分, 不要上来就把海量的全国数据丢进去. 比如按照地区划分, 成都的就找成都范围的. 范围按照实际需要来, 1km就是1km,3km就是3km, 10km就是10km. 不要上来为了方便直接10km. 10km就应该讨论到底是哪种场景我需要去10km内找数据. 是不是用关键字更方便? 采集到的数据量和负载成倍增长
-
主页展示型App或者web应用, 核心需要关注主页数据接口的缓存命中率, 不要本来是整个成都投放了一个广告, 结果每个用户都去db做一次逻辑查询, 做一个地区维度的缓存不是很好. 广告业务善于使用预准备数据.
-
根据用户定位数据做的推荐功能, 虽然用户位置在移动, 但是也不要每次都重新计算重设缓存. 和产品约定, 用户和上次移动距离多少米内(比如50m,10m), 不做二次数据分析, 使用上次缓存, 提高缓存命中率, 大部分业务场景下 没有需要用户没移动1M就变更数据的. 产品逻辑正常的情况下, 不要为了万分之一的可能性体验提升, 让其他的万分之9999用户,都带来处理过慢的异常体验和没必要的服务器开销.
-
做广告投放推送生效功能时,可以加一个定时数据补偿机制,可以让你在接收方异常或数据丢失时高枕无忧。
-
提供给第三方api需要鉴权时候,提供一个appid和appkey比只给一个appkey好。就算是md5也保留这个设计可以让你以后扩展的更方便。
-
善于封装和抽象, 方便自己未来开发的更轻松, 减少代码量, 也方便维护和统一优化管理. 同一个基础工具不应该在一个项目中出现多次. N个MD5, N个DES, N个AES, N个HttpClient. 一句 网络异常, 请稍后重试的文案 在工程中出现几百处 还是很尴尬的
retrun xxx.getRsBean(ResultCodeEnum.SUSS,obj); 何不再封装一个 retrun success(obj) or xxx.success(obj); if(result.getCode() == ResultCodeEnum.SUSS){} 何不再提供一个 result.isSuccess();方法
-
定制化配置不要过多. 比如公网服务器间api访问鉴权应该尽可能的使用统一的代码级授权规则, 不要为了图一时方便在nginx做ip限制这样类似的操作. 除非有专人做服务器业务间访问策略记录和维护, 否则服务器变更时容易遗漏或失效.
-
同一个主项目业务基础功能常量不要分开定义,应该有默认的base来定义. 特别是响应的result对象和code定义. 不要有的code=0是成功, 有的code=1是成功. 有的叫msg有的叫message. 一个参数异常的code, 在多个模块中定义出4, 5个不同的code码, 基础CODE应该提前统一定义. 导致多人协作开发, 出现细节问题.
-
为了保持代码整洁美观, 习惯性开发完成后, 使用ide全选后 ctrl+alt+l格式化代码. 当然如果担心影响别人的代码选中自己的代码即可.
-
关注ide给你代码加了下划线和颜色的地方. 像Reqeust这种单词误写, 过期方法, 未调用的方法, 过多重复, 代码不够优雅大部分 均可以正确提示给你.
-
善用lombok, @Data @@Slf4j 这些基本命令会让你的代码看着更舒服.
-
善用断言做参数验证,不需要大量的 if(a == null || a==0 || bxxxx){ throw new } 直接编写一个统一的断言处理, 并且抛出对应的参数异常即可. 比如:isPositiveNumber(@Nullable Number... keys) 判断多个数字是否是正数, notBlank(@Nullable String... keys) 判断多个字符串notBlank.
-
异常处理
1. 关于异常处理不能try catch 后不做任何处理,要么抛出给调用方, 要么该做日志记录告警及数据回滚等操作的一定要做处理. 否则默认推荐抛出异常, 由上层处理 2. 不要直接上来就做无意义的 e.printStackTrace(); 这是不负责的表现 3. 另外注意你的自定义异常如果继承的是RuntimeException 上层代码是不会要求强制捕获或抛出的, 继承Exception则需要上层强制处理. 但是如果遵循以上处理方式, 也无影响 4. 能够明确的异常类型尽量定义明确且统一, 因为上层有时候处理的时候他不知道你有什么异常类型, api返回给用户可能就是未知异常了. 体验极差
2. 常见问题及处理
-
为什么我的md5值和别人的md5值不一样?
往往因为传入来源字符串的编码问题导致 将md.digest(message.getBytes()) 改为md.digest(message.getBytes("UTF-8")) 即可
-
为什么我的base64编码和对方的base64编码不一致
关注一下对方或我方编码是否是每隔76会有一个换行符, 如果你是用的sun.misc.BASE64Decoder则会有换行符, 如果使用jdk8的java.util.Base64则没有换行符(推荐为了避免base64各种编码和url问题, 直接使用16进制编码. 如果一定要使用, 推荐用jdk8的, 性能更高)
-
简单几步检测服务器负载状态
首先top 找到进程pid(ps -ef | grep java,ps -ef | grep tomcat) 1. jstack 1.1 top -Hp {pid} -> 比如可以找到cpu很高的具体线程id 1.2 printf "%x\n" {id} ->将线程id转16进制 1.3 jstack {pid} | grep -A 20 {id16} -> 查看线程堆栈信息 1.4 jstack -l {pid} > jstack.tdump -> 导出完整线程堆栈信息 1.5 windos可以使用{jdkPath}/bin/jvisualvm.exe 装载该文件辅助分析 2. jstat -gcutil {gid} 2000 ->每2秒打印gc信息(关注频繁fgc导致cpu占用过高,轻量的面向用户业务0次状态就比较好,当然不是绝对) 3. jmap 内存排查 3.1 jmap -histo:live {pid} | head -n 100 -> 查看top 100的内存占用对象. 3.2 jmap -heap {pid} -> 可以查询当前各内存状态,总量和剩余. (资源是否吃紧) 3.3 jmap -dump:format=b,file=jmap.hprof {pid} -> 将当前内存堆详情导出,文件可能会比较大,可以压缩后下载. 3.4 windos可以使用{jdkPath}/bin/jvisualvm.exe 装载该文件辅助分析 4. jinfo -flags {pid} -> 可以查看当前jvm运行实际生效的参数配置.(检查配置未生效) 5. java -XX:+PrintFlagsFinal -version | grep ParallelGCThreads -> 可以查询参数名和默认值
- springboot2.1.0以下版本RedisTemplate没有setIfAbsent(K key, V value, long timeout, TimeUnit unit)方法,不想换jedis或者lettuce,但是又想用分布式锁怎么快速实现
加锁也使用lua脚本即可 String LUA_LOCK = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end"; String LUA_UNLOCK = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; redisTemplate.execute(RedisScript<T> script, List<K> keys, Object... args) //附jedis版核心方法 加锁:set(String key, String value, String nxxx, String expx, long time) 加锁:jedis.eval(script, keys, args); script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" //附lettuce版核心方法 加锁:commands.set(lockKey, lockId, SetArgs.Builder.nx().ex(expireTimeSec)); 解锁: String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; commands.eval(script, ScriptOutputType.INTEGER, new String[]{lockKey}, requestId);
-
开发测试环境有时候批量删除redisKey大家都知道怎么操作,那批量删除非0库的命令呢?
redis-cli -a {pwd} -n {idx} keys "xxx_*" | xargs redis-cli -a {pwd} -n {idx} del
-
为什么到点了job应该到时间生效的数据没有生效?
这里有时挺坑的,看看是不是服务器没有时间校正对时,服务器的时间还没到点。特别是测试环境,测试问到你这个问题,你对自己代码很有把握的话,让测试自己先看看服务器时间。测试有时候改了时间忘记改回去。
-
为什么运维线上机器设置了crontab但是我却没找到设置信息?
crontab按用户设置的,让运维看看是不是用root设置了,你用的是dev账号查看
-
将自己的jar上传到maven公库的时候,为啥gpg公钥发布后,但是公库一直提示找不到公钥。
gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys ;国内网络可以试试替换为 hkp://keyserver.ubuntu.com
-
请求第三方api出现readTimeOut,但是对方说已正常响应,并且拿出了日志怎么快速确认问题?
有一个小细节可能会被忽略,请先做一下双方日志对时。我方发出时间,对方接收到的时间,我方超时的时间点,对方响应的时间点。也许就是对方是有响应日志,但是是在我们超时后。他有响应日志并不能证明他没有超时。注意时间对比
-
App复杂功能业务测试阶段有问题,排查要看很多地方,但是你很自信后端代码没问题,怎么节约时间?
只要这个功能你没有做任何的os区别,请让测试进行android和ios操作对比,是否是一端对一端不对。往往很多时间不能保证ios和android出的问题都一样,很可能是一个有A问题一个有B问题,没必要每次都需要后端介入,只有双端确认无问题或确认接口数据确实有问题,后端才需要介入。这样不论是研发还是测试效率都更高
-
App开发中,为什么嵌入的H5显示展示错误或者一片空白。
请App检测是否统一捕获了前端框架返回js的异常做了统一处理。这里注意只要不是无法访问加载,js异常app不应该一改而论捕获处理,特别是接入第三方广告。比如b站一个子模块要拉起自己的函数,没有会有一个js异常,但是不影响整个业务和界面。虽然这里js不应该抛出,但是我们的兼容也应该做好,广告方推动修改效率不会有你想象的那么高
网友评论