问题描述
最近项目上碰到使用httpClient客户端请求时,服务端总是不能拿到完整的请求头,经过了反复的修改请求头的名称及值,结果服务端依然无法完整拿到请求头(请求传了15个请求头,服务端可能只能拿到13个)
问题分析
- 可能是框架问题
- 可能是请求头规范问题
框架问题的尝试
使用main方法,替代框架笨重的代码,将header写死发送get请求给服务端,经过测试服务端能拿到完成的请求头,此时笃定是请求头的内容的问题,也就是第2点请求头中的名称规范或者值的问题
请求头问题的尝试
经过框架问题的尝试后,排查请求头。发现请求头中"sendData: test-mydata hello\r\n", 如
access-control-allow-credentials: true
access-control-allow-methods: GET,HEAD,PUT,POST,DELETE
access-control-allow-origin: https://test.163.com
content-length: 127
content-type: application/json; charset=utf-8
date: Thu, 13 Aug 2020 12:05:10 GMT
sendData: test-mydata hello
server: nginx
status: 200
strict-transport-security: max-age=15768000
可以看到\r\n导致请求头的格式增加了换行符。由于请求头sendData的值为Base64.encodeBase64String加密后的值,Base64.encodeBase64String在加密后超过76字节,要添加回车换行符。
问题总结
问题的根本原因是请求头中的内容有特殊符号导致了请求头的格式发生了变化,破坏了http协议的结构。
客户端发送一个HTTP请求到服务器的请求消息包括请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。如下图
最终使用代码替换Base64加密后的字符串中的\r\n
String sendDataStr=Base64.encodeBase64String("sendData".getBytes()).replaceAll("\r|\n","")
这里也可以得出一个结论:当一个请求的请求头只能拿到部分值时,很可能是请求头中的某个值的格式不正确破坏了Http协议的结构