点击关注公众号:互联网架构师,后台回复 2T获取2TB学习资源!
上一篇:2T架构师学习资料干货分享
国庆节,有网友给我连线,说他遇到了一个奇怪的 bug,请教我远程提供帮助。我这里记录一下,他遇到的问题,分享给大家!
![6e8783e7c50e8f7eda836ce1befdba21.jpeg](https://i-blog.csdnimg.cn/blog_migrate/d92b5fe684fbe4fa888bd95730ca2342.jpeg)
背景
网友所在的部分,前端和测试反馈说登录功能出现 bug。通过 F12 定位到是 getUserInfo 接口返回 400。
重点是这个接口的报错和登录的账号有关,有些账号报 400,有些账号报 403,还有些账号登录成功。
![1922a9bf5d90c3599430e7c46640171e.jpeg](https://i-blog.csdnimg.cn/blog_migrate/81fc04fd2d1d78a0293357fcaa3d168f.jpeg)
![e53c6f3f200f065cd5c9458d77b84aed.jpeg](https://i-blog.csdnimg.cn/blog_migrate/cc45110df6c1dac796687d43b54652f0.jpeg)
然后我通过 postman 请求,不管什么账户都能成功。而使用前端页面请求的确和前端测试反馈的一致,这点就非常奇怪。
定位问题
通过向日葵远程,我发现页面 403 的请求明显没有传 authorization 字段,所以返回 403 是正常的,但是没有问他具体为什么登录接口有返回 token,然后前端没有带上。
400 的问题比较奇怪,没有任何 response,只有一个 status code 是 400。
因为异常和请求的账号有关,所以考虑到会不会是 token 不一样,解析出 token 内部的数据导致的 bug,但是使用 postman 请求缺没有问题。
postman 请求和浏览器请求的不同点就在于浏览器请求还带上了很多的 header 参数,postman 由于是我后端自己测试,所以只添加了基本的 authorization 和 Content-Type。
偶然间,我发现,这位网友的 token 都非常的长,这 jwt 是带了多少东西,让 token 这么长。
我想起了 Nginx 服务器默认的 header 长度上限是 4k,如果超过这个值,Nginx 就会直接返回 400。于是,我通过修改默认的 header 上限值,验证了,确实是这个问题。
一般来说可以通过以下 2 个参数来调整 nginx 的 header 上限。
client_header_buffer_size 16k
large_client_header_buffers 4 16k
原因
由于他在加密 token 的时候将太多数据添加到 payload 里了,导致 token 过长。
403 是由于 token 过长,超过了浏览器支持的最大上限,所以根本添加不上去。
400 也是因为 token 过长,只不过没有超过浏览器的上限。但是加上其他的 header 参数,总长度超过了 Nginx 服务的默认长度上限。
解决方法
缩小 header,将多余的数据从 payload 中剔除,token 就会变短。要修改代码
修改 Nginx header 的上限,短期解决方案
由于他比较着急,因此我建议他先修改 Nginx header 的上限的参数。
nginx处理header时的方法:
先处理请求的 request_line
之后才是 request_header
这两者的buffer分配策略相同。
先根据client_header_buffer_size配置的值分配一个buffer,如果分配的buffer无法容纳 request_line/request_header,那么就会再次根据large_client_header_buffers配置的参数分配large_buffer,如果large_buffer还是无法容纳,那么就会返回414(处理request_line)/400(处理request_header)错误。
如果你的请求中的header都很大,那么应该使用client_header_buffer_size,这样能减少一次内存分配。
如果你的请求中只有少量请求header很大,那么应该使用large_client_header_buffers,因为这样就仅需在处理大header时才会分配更多的空间,从而减少无谓的内存空间浪费。
针对get请求,解决请求串过长的问题:
针对 get 请求,我们可以通过修改另外两个配置来解决请求串超长的问题:
client_header_buffer_size语法:client_header_buffer_size size默认值:1k使用字段:http, server这个指令指定客户端请求的http头部缓冲区大小绝大多数情况下一个头部请求的大小不会大于1k不过如果有来自于wap客户端的较大的cookie它可能会大于1k,Nginx将分配给它一个更大的缓冲区,这个值可以在large_client_header_buffers里面设置。
large_client_header_buffers语法:large_client_header_buffers number size默认值:large_client_header_buffers 4 4k/8k使用字段:http, server指令指定客户端请求的一些比较大的头文件到缓冲区的最大值,如果一个请求的URI大小超过这个值,服务器将返回一个”Request URI too large” (414),同样,如果一个请求的头部字段大于这个值,服务器将返回”Bad request” (400)。缓冲区根据需求的不同是分开的。默认一个缓冲区大小为操作系统中分页文件大小,通常是4k或8k,如果一个连接请求将状态转换为 keep-alive,这个缓冲区将被释放。
那么有人就会觉得奇怪了,为什么修改http header的大小就能解决get请求串过长的问题呢,这就要从http协议的get请求说起了,其实GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头中)。
短期帮他解决了,后面我建议他要缩短 token 长度,不要什么东西都放到 token 中。
最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。
正文结束
推荐阅读 ↓↓↓
1.JetBrains 如何看待自己的软件在中国被频繁破解?