crm开发定制【远程调用返回400问题排查(已解决)】

返回400问题排查

前言

crm开发定制我最近给公司一个两年crm开发定制前开发的项目售后,crm开发定制帮助客户验视功能点,crm开发定制顺便帮助解决项目中的问题,crm开发定制由于原负责该项目的项crm开发定制目组已经全都离职了,crm开发定制导致验收之路漫长且艰苦…

crm开发定制在解决问题的过程中碰crm开发定制到了许多疑难杂症都一一解决了,唯独其中有一个问题让我和同事绞尽脑汁花了三天才得以解决,所以为了以后不再被这个问题困扰,特地记录一下,毕竟好记性不如烂笔头嘛,话不多说,我们接着往下看

发生问题由来

是这样一个问题,在测试的过程中发现某部分功能依赖的数据源有部分缺失的情况,然后就着手开始排查问题,调用链调用方式如下:

客户标识
获得请求token
RestTemplate
客户标识
我的服务
远程登陆
转发平台
客户服务1
客户服务2
客户服务3

问题排查

刚开始我觉得肯定是接口报错了,然后开了一个测试接口去调用远程访问方法,结果报错400 Bad Request!!!WTF?如果这个接口400那应该一条数据都没有才对啊,怎么一部分成功一部分失败??

1. 参数400

常见的400就是参数和定义的参数类型不一致导致参数400,然后我拿跑成功的数据作为条件传入,然后成功了,我觉得可能就是这个问题,然后又访问了一次然后也爆出400问题,然后接下去访问的都是400了,再换个成功的数据也无济于事,只要有访问通过的接口就说明肯定不是因为参数问题导致的400了,然后就去看转发平台的日志,也证实了没有爆出参数400的问题
ps:使用Postman调用也是畅通无阻…

2. 请求头过大导致400

通过查看转发平台日志,发现有个问题就是调用的接口要么访问到达,然后转发平台打出日志,要么什么反应也没有,然后我想到了是不是由于请求头过大的原因,然后我直接把所有参数都去掉然后直接访问,结果还是400,然后我又把请求头的token以及标识全去掉,结果终于在转发平台看到了unauthorization错误,果然是这个问题,然后我就询问负责转发平台的同事他们的Nginx设置请求最大大小是多少,然后被告知他们的平台没用到Nginx,那就是说刚刚那个就仅仅只是因为没有token报的错,跟请求头大小没有关系,到这再次断了线索…

然后我就往封装调用的各个地方都插入日志打印,想从日志中找出蛛丝马迹,在漫长的打印查看打印的过程中,终于让我逮住了问题的小尾巴,我在打印Header的内容时发现token的value是一个数组,且里面有两个token!!!

3. header异常400

在发现header异常后,我就仔细的去看封装好的代码,结果发现了下面这一串代码:

public HttpHeaders getHeaders() {	  HttpHeaders httpHeaders = new HttpHeaders();      httpHeaders.setContentType(MediaType.APPLICATION_JSON);      TokenHelp tokenHelp = tokenHelpRepository.findTokenByConsumerId("客户标识");      // 如果当前客户在数据库中没有token则取用默认的token      if (null == tokenHelp){          tokenHelp = tokenHelpRepository.defaultToken();      }      // 如果还是为空则取用登录token      if (null == tokenHelp){          LoginResponse loginResponse = getToken();          httpHeaders.add(HttpHeaders.AUTHORIZATION, BEARER + loginResponse.getToken());      } else {      	  // 如果不为空则设置token      	  httpHeaders.add(HttpHeaders.AUTHORIZATION, tokenHelp.getToken());      	  // 获得时间差          long diffMillis = System.currentTimeMillis() - tokenHelp.getCreateTime();          // 超过十分钟重新获取token          long outTime = 10 * 60 * 1000;          if (diffMillis > outTime) {              LoginResponse loginResponse = getToken();              httpHeaders.add(HttpHeaders.AUTHORIZATION, BEARER + loginResponse.getToken());          }          httpHeaders.add("consumerId", "客户标识");      }      return httpHeaders;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

以上代码乍看上去没什么问题,但是当我点击进HttpHeaders的实现:

package org.springframework.http;public class HttpHeaders implements MultiValueMap<String, String>, Serializable {  private static final long serialVersionUID = -8578554704772377436L;  // ...省略多行代码}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我看到了MultiValueMap,如果不了解MultiValueMap的同学可能觉得这没什么问题,Map装很正常啊,但是认识的同学都知道MultiValueMap 可以同一个key下面放多个value,原来的Map如果设置了同样的Key,那么值会被替换,但是当使用MultiValueMap时设置了同样的Key,那么值会被用一个数组装起来,为了方便大家理解,这里贴一段简单的演示代码:

public static void main(String[] args) {    MultiValueMap<String, String> valueMap = new LinkedMultiValueMap<>();    valueMap.add("1","1");    valueMap.add("1","2");    valueMap.add("1","3");    valueMap.add("1","4");    valueMap.add("1","5");    valueMap.add("2","1");    valueMap.add("2","2");    valueMap.add("3","1");    for (Map.Entry<String, List<String>> stringListEntry : valueMap.entrySet()) {        System.out.println(“key:+stringListEntry.getKey());        List<String> value = stringListEntry.getValue();        System.out.println("value:"+value);    }}输出结果:=================================================key:1value:[1, 2, 3, 4, 5]key:2value:[1, 2]key:3value:[1]输出结果:=================================================
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

结合之前的代码看这个问题

		  // 如果不为空则设置token      	  httpHeaders.add(HttpHeaders.AUTHORIZATION, tokenHelp.getToken());      	  // 获得时间差          long diffMillis = System.currentTimeMillis() - tokenHelp.getCreateTime();          // 超过十分钟重新获取token          long outTime = 10 * 60 * 1000;          if (diffMillis > outTime) {              LoginResponse loginResponse = getToken();              httpHeaders.add(HttpHeaders.AUTHORIZATION, BEARER + loginResponse.getToken());          }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

else代码块中,先设置了一遍AUTHORIZATION然后如果当前token过期了那么会再次设置一遍,这就导致了,如果在token过期的一段时间内,就会有少部分的请求头中有两个token,就会导致请求400,然后更改了设置token逻辑后,接口就顺利通车啦!!!

总结

在处理接口400问题的时候一定要擦亮眼睛,一步一步的去排查问题所在点,魔鬼永远藏在不经意发现的地方,好了,到这分享就结束了,写的不好大家多多谅解哈~

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发