- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在实际工作中,我们经常需要在项目中调用第三方API接口,获取数据,或者上报数据,进行数据交换和通信.
那么,调用第三方API接口会遇到哪些问题?如何解决这些问题呢?
这篇文章就跟大家一起聊聊第三方API接口的话题,希望对你会有所帮助.
。
一般我们在第一次对接第三方平台的API接口时,可能会先通过浏览器或者postman调用一下,该接口是否可以访问.
有些人可能觉得多次一举.
其实不然.
有可能你调用第三方平台的API接口时,他们的接口真的挂了,他们还不知道.
还有一种最重要的情况,就是你的工作网络,是否可以访问这个外网的接口.
有些公司为了安全考虑,对内网的开发环境,是设置了防火墙的,或者有一些其他的限制,有些ip白名单,只能访问一些指定的外网接口.
如果你发现你访问的域名,在开发环境访问不通,就要到运维同学给你添加 ip白名单 了.
很多第三方API接口为了防止别人篡改数据,通常会增加数字签名(sign)的验证.
sign = md5(多个参数拼接 + 密钥) 。
在刚开始对接第三方平台接口时,会遇到参数错误,签名错误等问题.
其中参数错误比较好解决,重点是签名错误这个问题.
签名是由一些算法生成的.
比如:将参数名和参数值用冒号拼接,如果有多个参数,则按首字母排序,然后再将多个参数一起拼接。然后加盐(即:密钥),再通过md5,生成一个签名.
如果有多个参数,你是按首字母倒序的,则最后生成的签名会出问题.
如果你开发环境的密钥,用的生产环境的,也可能会导致生产的签名出现问题.
如果第三方平台要求最后3次md5生成签名,而你只用了1次,也可能会导致生产的签名出现问题.
因此,接口签名在接口联调时是比较麻烦的事情.
如果第三方平台有提供sdk生成签名是最好的,如果没有,就只能根据他们文档手写签名算法了.
通过上面一步,我们将签名调通了,可以正常访问第三方平台获取数据了.
但你可能会发现,同一个请求,15分钟之后,再获取数据,却返回失败了.
第三方平台在设计接口时,在签名中增加了时间戳校验,同一个请求在15分钟之内,允许返回数据。如果超过了15分钟,则直接返回失败.
这种设计是为了安全考虑.
防止有人利用工具进行暴力破解,不停伪造签名,不停调用接口校验,如果一直穷举下去的话,总有一天可以校验通过的.
sign = md5(多个参数拼接 + 密钥 + 时间戳) 。
因此,有必要增加时间戳的校验.
如果出现这种情况,不要慌,重新发起一次新的请求即可.
如果你调用第三方平台的某个API接口查询数据,刚开始一直都有数据返回.
但突然某一天没返回数据了.
但是该API接口能够正常响应.
不要感到意外,有可能是第三方平台将数据删除了.
我对接完第三方平台的API接口后,部署到了测试环境,发现他们接口竟然没有返回数据,原因是他们有一天将测试环境的数据删完了.
因此,在部署测试环境之前,要先跟对方沟通,要用哪些数据测试,不能删除.
有些平台的API接口在请求之前,先要调用另外一个API接口获取token,然后再header中携带该token信息才能访问其他的业务API接口.
在获取token的API接口中,我们需要传入账号、密码和密钥等信息。每个接口对接方,这些信息都不一样.
我们在请求其他的API接口之前,每次都实时调用一次获取token的接口获取token?还是请求一次token,将其缓存到redis中,后面直接从redis获取数据呢?
很显然我们更倾向于后者,因为如果每次请求其他的API接口之前,都实时调用一次获取token的接口获取token,这样每次都会请求两次接口,性能上会有一些影响.
如果将请求的token,保存到redis,又会出现另外一个问题: token失效 的问题.
我们调用第三方平台获取token的接口获取到的token,一般都有个有效期,比如:1天,1个月等.
在有效期内,该API接口能够正常访问。如果超过了token的有效期,则该API接口不允许访问.
好办,我们把redis的失效时间设置成跟token的有效期一样不就OK了?
想法是不错,但是有问题.
你咋保证,你们系统的服务器时间,跟第三方平台的服务器时间一模一样?
我之前遇到过某大厂,提供了获取token接口,在30天内发起请求,每次都返回相同的token值。如果超过了30天,则返回一个新的.
有可能出现这种情况,你们系统的服务器时间要快一些,第三方平台的时间要慢一些。结果到了30天,你们系统调用第三方平台的获取token接口获取到了token还是老的token,更新到redis中了.
过一段时间,token失效了,你们系统还是用老的token访问第三方平台的其他API接口,一直都返回失败。但获取新的token却要等30天,这个时间太漫长了.
为了解决这个问题,需要捕获token失效的异常。如果在调用其他的API接口是发现token失效了,马上请求一次获取token接口,将新的token立刻更新到redis中.
这样基本可以解决token失效问题,也能尽可能保证访问其他接口的稳定性和性能.
系统上线之后,调用第三方API接口,最容易出现的问题,应该是 接口超时 问题了.
系统到外部系统之间,有一条很复杂的链路,中间有很多环节出现问题,都可能影响API接口的相应时间.
作为API接口的调用方,面对第三方API接口超时问题,除了给他们反馈问题,优化接口性能之外,我们更有效的方式,可能是增加接口调用的 失败重试机制 .
例如:
int retryCount=0;
do {
try {
doPost();
break;
} catch(Exception e) {
log.warn("接口调用失败")
retryCount++;
}
} where (retryCount <= 3)
如果接口调用失败,则程序会立刻自动重试 3次 .
如果重试之后成功了,则该API接口调用 成功 .
如果重试3次之后还是失败,则该API接口调用 失败 .
调用第三方API接口,偶尔因为参数的不同,可能会出现500的问题.
比如:有些API接口对于参数校验不到位,少部分必填字段,没有校验不能为空.
刚好系统的有些请求,通过某个参数去调用该API接口时,没有传入那个参数,对方可能会出现NPE问题。而该接口的返回code,很可能是500.
还有一种情况,就是该API接口的内部bug,传入不同的参数,走了不同的条件分支逻辑,在走某个分支时,接口逻辑出现异常,可能会导致接口返回500.
这种情况做接口重试也没用,只能联系第三方API接口提供者,反馈相关问题,让他们排查具体原因.
他们可能会通过修复bug,或者修复数据,来解决这个问题.
如果你在系统日志中发现调用的第三方API接口返回了404,这就非常坑了.
如果第三方的API接口没有上线,很可能是他们把接口名改了,没有及时通知你.
这种情况,可以锤他们了.
还有一种情况是,如果第三方的API接口已经上线了,刚开始接口是能正常调用的.
第三方也没有改过接口地址.
后来,突然有一天发现调用第三方的API接口还是出现了404问题.
这种情况很可能是他们网关出问题了,最新的配置没有生效,或者改了网关配置导致的问题.
总之一个字:坑.
之前我调过一个第三方的API接口分页查询数据,接入非常顺利,但后来上线之后,发现他们的接口少数据了.
一查原因发现是该分页查询接口,返回的 总页数 不对,比实际情况少了.
有些小伙伴可能会好奇,这么诡异的问题我是怎么发现?
之前调用第三方API接口分页查询分类数据,保存到我们的第三方分类表中.
突然有一天,产品反馈说,第三方有个分类在分类树中找不到.
我确认之后,发现竟然是真的没有.
从调用第三方API接口的响应日志中,也没有查到该分类的数据.
这个API接口是分页查询接口,目前已经分了十几页查询数据,但还是没有查到我们想要的分类.
之前的做法是先调用一次API接口查询 第一页 的数据,同时查出 总页数 。然后再根据总页数循环调用,查询 其他页 的数据.
我当时猜测,可能是他们接口返回的总页数有问题.
于是,可以将接口调用逻辑改成这样的:
验证之后发现这样果然可以获取那个分类的数据,只能说明第三方的分页查询接口返回的总页数比实际情况小了.
我之前调用过某平台的API接口获取指标的状态,之前根据双方约定的状态有: 正常 和 禁用 两种.
然后将状态更新到我们的指标表中.
后来,双方系统上线运行了好几个月.
突然有一天,用户反馈说某一条数据明明删除了,为什么在页面上还是可以查到.
此时,我查我们这边的指标表,发现状态是正常的.
然后查看调用该平台的API接口日志,发现返回的该指标的状态是: 下架 .
what?
这是什么状态?
跟该平台的开发人员沟通后,发现他们改了状态的枚举,增加了:上架、下架等多个值,而且没有通知我们.
这就坑了.
我们这边的代码中判断,如果状态非禁用状态,都认为是正常状态.
而下架状态,自动被判断为正常状态.
经过跟对方沟通后,他们确认下架状态,是非正常状态,不应该显示指标。他们改了数据,临时解决了该指标的问题.
后来,他们按接口文档又改回了之前的状态枚举值.
不知道你在调用第三方接口时,有没有遇到过接口时好时坏的情况.
5分钟前,该接口还能正常返回数据.
5分钟后,该接口返回503不可用.
又过了几分钟,该接口又能正常返回数据了.
这种情况大概率是第三方平台在重启服务,在重启的过程中,可能会出现服务暂时不可用的情况.
还有另外一种情况:第三方接口部署了多个服务节点,有一部分服务节点挂了。也会导致请求第三方接口时,返回值时好时坏的情况.
此外还有一种情况:网关的配置没有及时更新,没有把已经下线的服务剔除掉.
这样用户请求经过网关时,网关转发到了已经下线的服务,导致服务不可用。网关转发请求到正常的服务,该服务能够正常返回.
如果遇到该问题,要尽快将问题反馈给第三方平台,然后增加接口失败重试机制.
。
之前还遇到一个第三方平台提供的API查询接口,接口文档中明确写明了有个 dr 字段表示 删除状态 .
有了这个字段,我们在同步第三方平台的分类数据时,就能够知道有哪些数据是被删除的,后面可以及时调整我们这边的数据,将相关的数据也做删除处理.
后来发现有些分类,他们那边已经删除了,但是我们这边却没删除.
这是啥情况呢?
代码逻辑很简单,我review了一下代码,也没有bug,为什么会出现这种情况呢?
追查日志之后发现,调用第三方平台获取分类接口时,对方并没有把已删除的分类数据返回给我们.
也就是说接口文档中的那个dr字段没有什么用,接口文档和接口逻辑不一致.
这个问题估计好多小伙伴都遇到过.
如果要解决这个问题,主要的方案有两种:
我们调用过百度的票据识别接口,可以自动识别发票信息,获取发票编号和金额等信息.
之前是另外一个同事对接的接口,后来他离职了.
发票识别功能上线,使用了很长一段时间,一直都没有出问题.
后来,某一天,生产环境用户反馈发票识别不了了.
我查询了相关服务的日志,没有发现异常,这就奇怪了.
打开代码仔细看了一下,发现那位同事的代码中调用第三方的API接口,接收响应数据时,直接转换成了对象,没有打印当时返回的字符串.
莫非,接口返回值有问题?
后来,我增加了日志,打印出了该接口真正的返回内容值.
原因一下查到了,原来是欠费了.
如果出现该了异常,百度的API接口返回的数据结构,用之前那位同事的实体有些参数没法获取到.
这是一个不小的坑.
我们在接收第三方API接口返回数据时,尽可能先用字符串接收返回值,然后将字符串转换成相应实体类,一定要将该返回值在日志中打印出来,方便后面定位问题.
不要直接用实体对象接收返回值,有些API接口,如果出现不同的异常,返回的数据结构差异比较大.
有些异常结果可能是他们网关系统直接返回的,有些异常是他们业务系统返回的.
其实,我们之前还遇到过其他坑,比如:调用分类树查询接口,但第三方返回的数据有重复的id,我们这边该如何处理这种异常数据呢?
我们在job中循环调用第三方API接口获取数据,如果其中某一次调用失败了,是try/catch捕获异常呢?继续执行后面的调用,还是直接终止当前的程序?如果try/catch如何保证数据一致性?终止当前程序,该如何处理后续的流程?
。
如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力.
求一键三连:点赞、转发、在看.
关注公众号:【苏三说技术】,在公众号中回复:面试、代码神器、开发手册、时间管理有超赞的粉丝福利,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习.
最后此篇关于我调用第三方接口遇到的13大坑的文章就讲到这里了,如果你想了解更多关于我调用第三方接口遇到的13大坑的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我对 c# 有点陌生,我在尝试围绕这个 if-then 语句尝试实现时遇到了一些麻烦。 这是我的目标:当用户将订单输入系统时,将为每个订单创建一个唯一的 orderID。但是,一些附加功能是用户可以选
我已经搜索了这个特定的错误,发现根本问题涉及循环计数错误并导致程序超出数组的界限。 但是,当我将每个数组降低到数组开始丢失输出数据的程度后,它继续抛出相同的错误。我对 C/C++ 仍然是新手,但任何对
我不明白为什么我运行这个小程序时屏幕上没有任何显示? while 循环甚至开始了吗? #include #include int main() { char word[20]; char
我接手了一个用 Perl 编写的项目,它有一些依赖项,例如 Template::Toolkit , Image::ExifTool , 和 GD仅举几例。目前,这些依赖项使用 --prefix 构建到
我想对一个字段进行累积总和,但只要遇到 0 就重置聚合值。 这是我想要的一个例子: data.frame(campaign = letters[1:4] , date=c("jan","
不久前,该项目的 gradle 构建运行良好,但现在一直失败并显示以下错误(带有 --info 标志的输出): Starting process 'Gradle Test Executor 1'. W
我是编程新手,想用 Java 制作一个掷骰子程序来执行。代码如下: import java.math.*; public class Dices { public static int dice1=0
这个问题已经有答案了: What is a StringIndexOutOfBoundsException? How can I fix it? (1 个回答) 已关闭 5 年前。 我对 Java 完
这个方法一直抛出标题中的异常,我找不到原因,我已经通过连接创建了其他表,并且所有引用的表都已创建。我正在使用嵌入式JavaDB . private void createEvidenceTable()
我刚开始上课,这是我第三次尝试上课。我遇到了一个 NameError,我真的不知道如何解决。看看我的程序,看看你能不能帮忙。 import random import math import pyga
好吧,这是我的困境,我向 JFrame 添加了三个面板。第一个(不可见)第二个(可见)和第三个(不可见)..我使用第一个面板作为菜单,当您选择一个选项时,第一个面板被制作(可见),然后第三个面板被制作
我的部分代码遇到问题。如果我选择选项 A,它会运行并给我正确的答案,但是,如果我选择选项 S 或 M,它不会给我任何结果,只会去到它应该去的地方。已经尝试将 if 更改为 else if,但它显示“预
我这里有一些代码,但我正在努力解决它,因为我似乎无法掌握这个文件指针的东西。我对使用文件还很陌生。我见过类似的其他问题,并且尝试了对其他人有效的解决方案,但由于某种原因它们对我不起作用。这是出现问题的
我们有一个很大的应用程序,我们已经将 TODO 规则添加到质量门中,如果发现 TODO 注释,它会给出错误。如果我们只是删除 TODO 注释(这很可怕),它会起作用,但添加 TODO 注释的整个目的就
我正在尝试编写一个名为 isVowel 的函数,它接受一个字符(即长度为 1 的字符串)并在它是元音、大写或小写时返回“true”。如果该字符不是元音字母,该函数应返回“false”。 这看起来应该可
我一直在努力完成我正在做的这个小项目,但由于某种原因它无法正常工作。 问题是当我第一次访问该页面并单击出现在主要部分中的第一个链接时,它会根据需要显示弹出框。现在,当我点击另一天,例如星期天并尝试点击
我正在尝试制作一个 WPF 应用程序。我的窗口内有一个数据网格。我制作了另一个窗口,将新数据添加到我的数据网格中。虽然它按照我想要的方式工作,但我不断遇到异常。我的 MySQL 代码: using S
我试图在我似乎无法使 NSUserDefaults 正常工作的程序中保存几个首选项。如果有人可以查看我的代码并查看是否有任何错误,我们将不胜感激 NSString *kGameIsPaused = @
设置 SymmetricDS版本是3.9.1(也试过3.9.0) 设置是从 postgres 9.5.3 到 postgres 9.5.3 Windows 10 pc(客户端节点)到 Windows
经过长时间的努力,我终于(差不多)完成了我的java菜单程序。但是,我无法让我的返回更改功能在我的代码末尾工作。它给出了非常奇数的数字。有什么想法吗? 代码: import java.io.*; im
我是一名优秀的程序员,十分优秀!