一个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。


restTemplate.getInterceptors().add(
  new BasicAuthorizationInterceptor("username", "password"));

加上这一行代码后,运行程序,顺利的得到了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.


扩展阅读:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 155,770评论 4 358
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,116评论 1 286
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,656评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,372评论 0 201
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,704评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,166评论 1 204
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,535评论 2 306
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,259评论 0 193
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,882评论 1 236
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,218评论 2 239
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,760评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,126评论 2 249
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,667评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,935评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,644评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,171评论 2 265
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,119评论 2 258

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,079评论 18 139
  • 组织:中国互动出版网(http://www.china-pub.com/) RFC文档中文翻译计划(http://...
    Palomar阅读 1,529评论 0 6
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,277评论 6 344
  • 说我发朋友圈的文章是心灵鸡汤,看都不看直接忽略,感觉被嫌弃不被接纳,好难受好难受,厌恶、愤怒,又无奈。 你对我了解...
    周海双阅读 344评论 0 0
  • 如果你只愿意为爱付出两分 作者 王瑞 1 朋友如痴如醉的爱上了一个姑娘。 那姑娘我见过,论姿色只能算上中等偏上,1...
    瑞和她的浅岛繁花阅读 346评论 8 10