【spring boot】RestTemplate 链接带签名post请求 400 bad request

由于项目需要从服务端对第三方发起请求,而且第三方没有提供SDK的情况下,只能根据对方api文档发送请求了,对方接口的格式是:地址+签名,post请求上送具体参数的方式去请求对方服务。

背景

很简单的一个需求,然而开始就卡住了,在Apifox调用能正常返回数据,而一用restTemplate去请求,就报400错误。

org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Requestat org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:79)at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:122)at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:102)at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:778)at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:736)at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670)at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579)
...

Apifox能调通,而代码调不通,不外乎代码创建起来的https请求有问题

分析

本来没打算细究,出错了打算改用OkHttpClient试一下,还真调通了

    private void action(String uri){OkHttpClient client = new OkHttpClient();RequestBody body = null;body = RequestBody.create(MediaType.parse("application/json"), data);// data是jsonObject转的String数据Request request = new Request.Builder().url(uri).method("POST", body).addHeader("Content-Type", "application/json").build();try {Response execute = client.newCall(request).execute();System.out.println(execute);} catch (IOException e) {throw new RuntimeException(e);}}

感觉有点离谱,所以直接用抓包工具(这里用的是fiddler,刚学着用,踩了点坑)抓包一下

POST https://xxx/xx/request?AccessKeyId=xxx&Expires=xx&Signature=xxx&Timestamp=2023-12-11T03%253A39%253A36Z HTTP/1.1
Accept: application/json, application/*+json
Content-Type: application/json;charset=UTF-8
User-Agent: Java/1.8.0_221
Host: xxxxx
Connection: keep-alive
Content-Length: xx{"data":"0"}

返回数据是

HTTP/1.1 400 Bad Request
Date: Mon, 11 Dec 2023 03:39:38 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive9d
{"code":"","message":"日期格式错误,请使用yyyy-MM-ddTHH:mm:ssZ格式"}
0

很明显的错误提示“日期格式错误,请使用yyyy-MM-ddTHH:mm:ssZ格式”,回头看下上送的报文是“Timestamp=2023-12-11T03%253A39%253A36Z”,虽然不怎么熟悉url的编码解码,但是很明显%253A实际上是%3A既“:”,所以是因为时间被双重加密了,因为在拼接url的时候,我已经手动给时间进行了URL编码

URLEncoder.encode(String.valueOf(time), "UTF-8")

所以去掉后再来

POST https://xxx/xx/request?AccessKeyId=xxx&Expires=xx&Signature=***&Timestamp=2023-12-11T08:25:21Z HTTP/1.1
Accept: application/json, application/*+json
Content-Type: application/json;charset=UTF-8
User-Agent: Java/1.8.0_221
Host: xxxxx
Connection: keep-alive
Content-Length: xx{"data":"0"}

返回数据

HTTP/1.1 401 Unauthorized
Date: Mon, 11 Dec 2023 08:25:21 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive6c
{"error":{"code":"AuthFailure","message":"签名错误"}}
0

玩我呢…我不格式化它也不格式化,只能断点分析了。发现RestTemplate这里对url进行了处理

	@Override@Nullablepublic <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {// 这里getUriTemplateHandler调用了一个默认的处理器对url进行了处理URI expanded = getUriTemplateHandler().expand(url, uriVariables);return doExecute(expanded, method, requestCallback, responseExtractor);}

解决

所以,只要改变这个处理器就可以解决问题了

    @Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory();// 这里选择了不处理而是自己手动去处理编码了,所以就不再会出现之前的问题了uriFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);restTemplate.setUriTemplateHandler(uriFactory);// ...return restTemplate;}

总结

很多时候,其实在编码的时候会下意识自信自己编写的没有问题, 以至于在调试的时候很难去发现问题点(开始的时候,其实我先断点了请求,发现请求是成功出去了,也没能关注到%253A的问题,一个劲的根据其他文章说的协议、请求头什么的问题在尝试),所以当发现问题但又自认为自己没有问题的时候,不妨换个角度换个方式,或者重新从头写一遍(有时候逻辑多的时候,其实也不要怕,一边写一边复盘会比自己只干看着分析还可能好一点)当然具体情况要结合自己实际去行动了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/215315.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Word插件-好用的插件-PPT 素材该怎么积累-大珩助手

PPT 素材该怎么积累&#xff1f; 使用大珩助手中的素材库功能&#xff0c;将Word中的&#xff0c;或系统中的文本文件、图片、其他word文档、pdf&#xff0c;所有见到的好素材&#xff0c;一键收纳。 步骤&#xff1a;选中文件&#xff0c;按住鼠标左键拖到素材库界面中&…

React-router-dom v6和 v5版本“注册路由”的差异化

React-router-dom v6和 v5版本“注册路由”的差异化 Matched leaf route at location “/about” does not have an element. This means it will render an with a null value by default resulting in an “empty” page. v6版本中Switch已经被换成了Routes&#xff0c;点击链…

【软考】信息系统项目管理师论文方向猜想

报喜不报忧&#xff0c;每天都在为鸡零狗碎推诿扯皮&#xff0c;属实是有辱师门。 通过软考&#xff0c;目前算是真正有意义的事情。 虽然都说高项的论文是个玄学&#xff0c;但是道听途说了一些通关感想还是蛮有启发的。 文件要求 参考了一份广西省高级工程师评审的文件&am…

Leetcode704二分查找、折半查找(Java实现)

好久没有更新算法题&#xff0c;今天来写一道二分查找的题目。题目要求如下&#xff0c; 那么这道题的解题思路如下&#xff0c;我们寻找的过程是首先去访问数组的中间位置mid&#xff0c;如果nums[mid]大于了targe那么说明&#xff0c;我们要找的数在mid的左半边&#xff0c;…

IAR开发stm8系列,C语言实现16位乘法器和32位除法器函数

stm8是8位单片机&#xff0c;在ADC采样采用12bit采样值进行定点整型运算的时候&#xff0c;为了保证精度需要通过16位乘法器 进行扩大&#xff0c;通过32位除法器缩小运算。但是用c语言直接用“*"和"/"计算是无法实现。c语言的math函数库也没有提供这样的计算函…

CSDN博客迁移至Hexo

实现思路&#xff1a; 获取博客列表获取博客详情解析博客详情html&#xff0c;找出 #article_content部分通过jsoup解析博客内容&#xff0c;转成md格式文件 依赖 <dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</art…

Linux实用操作篇-下篇

Linux实用操作篇-上篇&#xff1a;Linux实用操作-上篇-CSDN博客 一、网络传输 1.1 ping命令 网络是否可联通 可以通过ping命令&#xff0c;检查指定的网络服务器是否是可联通状态 语法: ping [-c num] ip或主机名 选项&#xff1a;-c&#xff0c;检查的次数&#xff0c;…

嵌入式SOC芯片选型

摘要&#xff1a; 本文主要探讨的是如果涉及芯片选型&#xff0c;需要考虑哪些方面&#xff1f; 将相关的需求列出来&#xff0c;供后续实践的时候参考。 SOC芯片选型 能力参数指标备注算力编码能力VPU处理能力YUV算法资源媒体audiovideoCPU运行主频架构DDRDDR规格DDR带宽DD…

cmake常用设置命令及参数大全

CMake是一个跨平台的开源构建工具,用于管理软件项目的构建过程。它使用简单的配置文件(CMakeLists.txt)来定义构建过程的规则。 以下是一些常用的CMake设置和命令: 1. cmake_minimum_required(VERSION x.x):指定需要的CMake版本。 2. project(project_name):设置项目的…

深入理解Java虚拟机---垃圾收集算法

深入理解Java虚拟机---垃圾收集算法 如何判定对象是否存活引用计数法可达性分析法 Java引用类型垃圾回收算法标记-清除算法复制算法标记-整理算法分代收集算法 HotSpot的算法实现枚举根节点安全点安全区域 如何判定对象是否存活 引用计数法 引用计数算法利用额外的内存空间来…

Dockerfile创建镜像介绍

1.介绍 Docker 提供了一种更便捷的方式&#xff0c;叫作 Dockerfile&#xff0c;docker build命令用于根据给定的Dockerfile构建Docker镜像。 docker build语法&#xff1a; # docker build [OPTIONS] <PATH | URL | -> 常用选项说明 --build-arg&#xff0c;设置构建时的…

上海亚商投顾:沪指探底回升 AI应用方向再度爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日探底回升&#xff0c;早盘一度均跌超1%&#xff0c;午后集体拉升翻红&#xff0c;深成指、创业板…

FFmpeg的AVcodecParser

文章目录 结构体操作函数支持的AVCodecParser 这个模块是AVCodec中的子模块&#xff0c;专门用来提前解析码流的元数据&#xff0c;为后面的解码做准备&#xff0c;这一点对cuda-NVdec非常明显&#xff0c;英伟达解码器的元数据解析是放在CPU上的&#xff0c;所以就非常依赖这个…

为什么Vue3的proxy需要Reflect呢

何为proxy Proxy 对象用于定义或修改某些操作的自定义行为&#xff0c;可以在外界对目标对象进行访问前&#xff0c;对外界的访问进行改写。 var proxy new Proxy(target, handler)ES6 中的proxy目前提供了13种可代理操作拦截的行为。 何为reflect ES6 标准中&#xff0c;…

远程工作:自由职业者如何成功赚钱

前言 在这个不断进步的数字化时代&#xff0c;远程工作已经从一个可选的边缘工作方式&#xff0c;成长为主流职业趋势的一部分。特别是自从全球疫情改变了我们的生活和工作方式以来&#xff0c;远程工作的概念不再是遥不可及的理想&#xff0c;而是已经成为许多人日常工作的现…

SpringBoot集成swagger2配置权限认证参数

作者简介&#xff1a;大家好&#xff0c;我是撸代码的羊驼&#xff0c;前阿里巴巴架构师&#xff0c;现某互联网公司CTO 联系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗…

[Java][JDK5]可变参数

我们可以假设一种情况&#xff0c;我们需要进行求和计算 在原先&#xff0c;我们考虑到参数只能传入一个数字&#xff0c;因此我们会将需要求和的数字放在一个数组&#xff0c;传入该数组进入方法再拆分计算 比如下面的例子:使用了增强for来对数组进行遍历 public class Mai…

【Lidar】基于Python的三维点云数据转二维平面+散点图绘制

最近一直在搞点云相关的操作&#xff0c;有时候在处理点云数据时需要查看处理后的数据是否满足需求&#xff0c;所以就想着写一套展示点云的代码。之前已经分享过如何可视化点云了&#xff0c;感兴趣的可以自己去看下&#xff1a;【Lidar】基于Python的Open3D库可视化点云数据。…

golang https server如何设计方便抓包定位且安全

代码 测试 用go写后端https服务时&#xff0c;需要定位https包中的内容是否符合预期。 有涉猎的朋友应该了解过https有一种keylog技术&#xff0c;它允许在HTTPS连接中捕获和记录SSL或TLS会话密钥&#xff0c;以便于调试和分析加密流量。 本文将的就是通过可控制开启和关闭的…

单身狗(Python)

题目描述 单身狗 “单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人&#xff0c;以便给予特殊关爱。 输入格式&#xff1a; 输入第一行给出一个正整数 N&#xff08;≤50000&#xff09;&#xff0c;是已知夫妻/伴侣的对数&#xff1b;…