生产问题:面试官你别再问解决过什么生产问题了!

生产:400 Bad Request

  • 问题描述
  • 为啥要看RFC?
  • 问题复现
  • 总结

最近有同学在生产环境部署服务后,突然出现了很多400 BadRequest的问题,这个问题搞了两天最后还是搞定了!收获了信心,增长了姿势!迫不及待想分享下这个问题的思路历程。

问题描述

这个问题从早上开始看到下午找到了答案,先把问题的现象描述下:

消费端在进行rpc调用后,发生了400错误,经过抓包发现了请求头很奇怪,有一些非KV结构的属性在头里边,顿时陷入了困惑!
生产问题:面试官你别再问解决过什么生产问题了!_第1张图片

如果是你,你会如何定位这个问题,你觉得这个问题原因是什么?
一开始,通过抓包看到非法头的时候,并不能确定这就是问题根源,不确定的原因是不了解http协议的请求头是否严格遵照KV键值对,所以就打算自己模拟一下wireshark抓包的请求头的现象。由于请求头每一行都是CRLF即换行符来分隔的,所以我先用curl的-H来添加一个没有value只有key的头,而且没有冒号(注意这个冒号,非常关键)。但是发现curl每次请求都是成功的,而且抓包结果显示这个只有Key没有Value也没有冒号的头根本就没有被传递到服务端,应该是curl命令对它进行了过滤。
既然curl不行,那我就用java代码模拟,通过对HttpClient设置头来模拟,思路就是设置正常头的同时在value后边加上\r\n和只有key的头。但很遗憾,这个只有key的头并不会独立作为一行,而是value的一部分。坑爹!模拟又失败了!

为啥要看RFC?

既然模拟不出来,那就不能确定这种只有Key的Header是否真的不合法?really?没有经过官方证实的都不可信,于是下午时突然想到了查看RFC,因为RFC是协议规范的官方定义,通过谷歌找到了RFC2616,在上边看到下边的描述:

4.2 Message Headers

HTTP header fields, which include general-header (section 4.5),
request-header (section 5.3), response-header (section 6.2), and
entity-header (section 7.1) fields, follow the same generic format as
that given in Section 3.1 of RFC 822 [9]. Each header field consists
of a name followed by a colon (" and the field value. Field names
are case-insensitive. The field value MAY be preceded by any amount
of LWS, though a single SP is preferred. Header fields can be
extended over multiple lines by preceding each extra line with at
least one SP or HT. Applications ought to follow “common form”, where
one is known or indicated, when generating HTTP constructs, since
there might exist some implementations that fail to accept anything

RFC2616地址:https://www.ietf.org/rfc/rfc2616.txt
也就是说Http协议规定,请求头是要以这样的形式来存入的。然后,在谷歌上输入"httpUrlConnection invalid header without colon".进行搜索,果然找到了,第一篇就是:
生产问题:面试官你别再问解决过什么生产问题了!_第2张图片
地址:https://bugs.openjdk.java.net/browse/JDK-8185898
生产问题:面试官你别再问解决过什么生产问题了!_第3张图片
发现这个400的问题是在当connection.setRequestProperty(key, null)调用时发生的,这篇issue给出了说明,是jdk版本的问题,里边给出的描述是1.8.0_131,问题在emb-8u241已经fixed:

Description
FULL PRODUCT VERSION : java version “1.8.0_131” Java™
SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot™ 64-Bit
Server VM (build 25.131-b11, mixed mode)


ADDITIONAL OS VERSION INFORMATION : Microsoft Windows [Version
6.1.7601]


A DESCRIPTION OF THE PROBLEM : If setRequestProperty method is called
on HttpURLConnection object with non-empty “key” and “value” set to
null, the corresponding HTTP header is inserted into the request, but
without “:” (colon). The header name passed via “key” is directly
followed by CR LF. This is violation of HTTP protocol, since colons in
headers are mandatory.

问题复现

里边还给出个重现的例子:

import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

class Test1 {
     
  public static void main(String[] asArguments) throws MalformedURLException, IOException {
     
    URL rURL = new URL(asArguments[0]);
    URLConnection rConnection = rURL.openConnection();
    rConnection.setRequestProperty("MyHeader", null);
    BufferedReader in = new BufferedReader(new InputStreamReader(rConnection.getInputStream()));
    String inputLine;
    while ((inputLine = in.readLine()) != null) System.out.println(inputLine);
    in.close();
  }
}

我把本地jdk切换到1.8.0_131,运行示例,果然证实了是jdk版本的问题。也就是对应到开头给出的wireshark抓包的报文:
生产问题:面试官你别再问解决过什么生产问题了!_第4张图片

总结

从这个例子可以看到,官当文档的权威性可以让我们对问题进行剪枝,缩小问题范围,瞄准问题的方向,然后利用谷歌强大的搜索能力,当然也得会输入合适关键词,比如我的英文一般般,但搜索问题其实不需要严格的语法。谷歌+RFC官方文档,这就是这个生产问题解决的杀手锏,看起来也没啥。哈哈!但是其实还是思路决定了出路!

你可能感兴趣的:(代码记录,400BadRequest,Http协议,RFC,生产问题,面试)