一个HTTP Basic Authentication引发的异常
这几天在做一个功能,其实很简单。就是调用几个外部的API,返回数据后进行组装然后成为新的接口。其中一个API是一个很奇葩的API,虽然是基于HTTP的,但既没有基于SOAP规范,也不是Restful风格的接口。还好使用它也没有复杂的场景。只是构造出URL,发送一个HTTP的get请求,然后给我返回一个XML结构的数据。
我使用了Spring MVC中的RestTemplate作为客户端,然后引入了Jackson-dataformat-xml作为xml映射为对象的工具库。由于集成外部API的事情已经做了很多次了,集成这个API也是轻车熟路,三下五除二就完成了。
接下来为了验证连通性,我先在SoapUI里配置了该外部API的某个测试环境,尝试发送了一个Get请求,成功收到了Response。然后我把自己的程序运行起来,尝试通过自己的程序调用该API,结果返回了HTTP 500错误,即“internal server error”。
这可奇了怪了。我第一反应是程序中对外部API的配置和SoapUI中的配置不一样。我仔细对比了发送请求的URL,需要的HTTP header以及用作验证的username和password都是完全一致的。这个问题被排除。
接下来我想再仔细看看Response,能否找到什么蛛丝马迹。仔细查看了Response的header和body,发现header一切正常,body是个空的body,没有提供任何的可用信息。
然后我能想到的另一个解决方案就是联系该外部API的团队,让他们帮忙看看我发送了请求之后,为什么服务器会返回500。但可惜这是一个很老的服务了,找到该团队的人并且排期帮我看log至少要花好几天的时间了。而且既然SoapUI能调用成功,而应用程序却调用不成功,问题多半还是出在我们这。
接下来我想既然问题有可能出在我们这,那么肯定是request有差异。由于我发的是一个Get请求,没有body实体,URL又完全一样,那么问题很可能出在request的header上。这个API需要request中包含两个自定义的header,而我在SoapUI以及自己的程序中都已经配置了。那问题会在哪里哪?
既然在SoapUI里无法重现这个问题,我就使用了Chrome插件版的POSTMAN,通过它配置了该API的调用。然后奇迹出现了,我竟然在POSTMAN中重现了这个问题。当我看到在POSTMAN也返回了500 error后,我思考了5秒钟,猜到了原因。问题很可能是出在了Authentication这个header上面。
要说这个问题,还要从HTTP的Basic Authentication说起。Basic Authentication是HTTP实现访问控制的最简单的一种技术。HTTP Client端会将用户名和密码组合后使用Base64加密,生成key为‘Authentication’,value为‘Basic BASE64CODE’的HTTP header,发送给服务器端以便进行Basic认证方式。
但这个经典的Basic Authentication是要经历两步的。第一步,客户端发送不带Authentication header的HTTP请求,服务器检查后发现受访的资源需要认证,就会返回HTTP Status 401,表示未授权,客户端发现服务器端返回401后,会再构造一个新的请求,这次包含了Authentication header,服务器接收后验证通过,返回资源。
那么我在自己的应用程序和POSTMAN中调用返回500 internal server error的原因是当第一次给Server发送不带Authentication header的HTTP请求时,Server竟然返回了HTTP Status 500。其实它应该返回401,这样HTTP Client会再发一个包含了Authentication的新请求。由于它返回了500,HTTP Client认为服务器有问题,就停止处理了。
那为什么在SoapUI中调用可以成功那?那是因为SoapUI使用的Http client在发第一次请求时就已经设置了Authentication header,所以就没有问题。这样可以避免重复发请求的现象。这种行为叫做‘preemptive authentication’(抢先验证),在SoapUI中你可以选择是否启用该行为。具体可以参见How To Authenticate SOAP Requests in SoapUI。
所以问题的根源在于该外部API在实现Basic Authentication时没有完全遵循规范,这锅我们不背。
解决方案有两种。第一种是让该外部API遵循Basic Authentication的规范,如果请求未授权应该返回401而不是500。不过我说过这是一个很古老的API了,让它们改要等到猴年马月了。
第二种就是我的应用程序在给该外部API发送请求时,第一次就设置Authentication header。我们用的是RestTemplate,而RestTemplate底层使用的是Apache Http Client 4.0+版本。要注入这个header很简单,在实例化RestTemplate后,给其多加一个Intecepter。
1 |
|
加上这一行代码后,运行程序,顺利的得到了Response,世界清静了。
最后一个问题,为什么Http Client当配置了用户名和密码后,不主动的启用‘preemptive authentication’那?毕竟可以少发很多请求啊。这是Apache官方给出的原因:
HttpClient does not support preemptive authentication out of the box, because if misused or used incorrectly the preemptive authentication can lead to significant security issues, such as sending user credentials in clear text to an unauthorized third party. Therefore, users are expected to evaluate potential benefits of preemptive authentication versus security risks in the context of their specific application environment.
Nonetheless one can configure HttpClient to authenticate preemptively by prepopulating the authentication data cache.
扩展阅读:
一个HTTP Basic Authentication引发的异常的更多相关文章
- 一个不当使用fclose引发的异常
最近服务器上一个后台传输文件的服务,经常会报出异常来,只能强行终止并重启. 昨天刚好有空,现场抓了一下dump,再把程序扔到IDA里看了一下,很快就找出原因了,原来是调用fclose时出错的. 使用C ...
- Web services 安全 - HTTP Basic Authentication
根据 RFC2617 的规定,HTTP 有两种标准的认证方式,即,BASIC 和 DIGEST.HTTP Basic Authentication 是指客户端必须使用用户名和密码在一个指定的域 (Re ...
- 网络负载均衡环境下wsHttpBinding+Message Security+Windows Authentication的常见异常
提高Windows Communication Foundation (WCF) 应用程序负载能力的方法之一就是通过把它们部署到负载均衡的服务器场中. 其中可以使用标准的负载均衡技术, Windows ...
- Atitit HTTP 认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结
Atitit HTTP认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结 1.1. 最广泛使用的是基本验证 ( ...
- Nancy 学习-身份认证(Basic Authentication) 继续跨平台
开源 示例代码:https://github.com/linezero/NancyDemo 前面讲解Nancy的进阶部分,现在来学习Nancy 的身份认证. 本篇主要讲解Basic Authentic ...
- WPF控件ComboBox 每个Item的ToolTip引发的异常
介绍 首先介绍下要实现的任务.做一个下拉框,当选择每个项的时候将鼠标发在上面显示该项的ToolTip的内容(Image). 实现 Model: public class SkinInfo : Noti ...
- HTTP Basic Authentication认证的各种语言 后台用的
访问需要HTTP Basic Authentication认证的资源的各种语言的实现 无聊想调用下嘀咕的api的时候,发现需要HTTP Basic Authentication,就看了下. 什么是HT ...
- 关于Cocos的内存管理机制引发一些异常的解决方案
错误:引发了异常: 读取访问权限冲突. this 是 0xDDDDDDDD.或者hero是 0xDDDDDDDD.hero是在GameController里创建的对象 这个的意思是this所指向的内存 ...
- HTTP Basic Authentication认证
http://smalltalllong.iteye.com/blog/912046 ******************************************** 什么是HTTP Basi ...
随机推荐
- ATM机运行代码
实现代码: import java.util.Scanner; public class Atm { public static void main(String[] args) { // TODO ...
- CubeMX使用及感受
简介 CubeMX这几年刚流行起来,是一个STM32代码的初始化配置工具,里面封装了硬件层.中间层,以及示例代码. cube使用 该软件的安装需要较高版本jdk支持,固件库安装时需要注意和主程序的版本 ...
- Python面试题解答
1. 一个谜题 >>> t = (1, 2, [30, 40]) >>> t[2] += [50, 60] 到底会发生下面 4 种情况中的哪一种? a. t变成(1 ...
- 天气类App原型制作分享-ColorfulClouds
ColorfulClouds是一款界面精美的天气预报App,它可以准确预报降雨量.污染程度等.这款App最美的是它的首页天气插画,扁平精美,同时配上了适当的动效,把普通的天气变得漂亮有趣,十分吸引眼球 ...
- print与printf的区别
print与printf的区别 1,print 中不能使用%s ,%d 或%c: 2,print 自动换行,printf 没有自动换行. 纯粹做下笔记哈!很多东西不知道,也就只能这样了!
- 【Java学习笔记之十九】super在Java继承中的用法小结
1)有人写了个很好的初始化属性的构造函数,而你仅仅想要在其中添加另一些自己新建属性的初始化,这样在一个构造函数中调用另外一个构造函数,可以避免重复的代码量,减少工作量: 2)在一个构造函数中调用另外一 ...
- HDU 2563 统计问题(递归,思维题)
统计问题 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- 最短路(spfa)
http://acm.hdu.edu.cn/showproblem.php?pid=2544 最短路 Time Limit: 5000/1000 MS (Java/Others) Memory ...
- Android studio启动后卡在refreshing gradle project(包解决)
这个问题几乎每个刚使用Android studio的同学都会碰到过,网上有各式各样的方法,有的说使用本地gradle,我试过多次,每次启动android studio时还是会检查更新,所以根本上解决的 ...
- virtualbox虚拟机NAT模式下不能连接外网
背景 给VirtualBox虚拟机(装载了Ubuntu16.04系统)配置了两张网卡,网络模式分别为"网络地址转换(NAT)"和"仅主机(Host-Only)适配器&qu ...