猜想原文:https://www.jianshu.com/p/4b1899316f49
问题描述
对crm进行二次开发的时候,接收腾讯广告平台推送线索的时候推送失败,后台未接收到请求,出现400错误码。
导致原因
腾讯方的推送服务在发请求的时候没有默认加host,请求我们的服务器的时候就会出现400错误,腾讯方告知手动添加host请求成功。
猜想
查阅相关资料后,有其他开发者也出现过类似问题,通常返回400错误码一般有两种情况:
1、语义有误,当前请求无法被服务器理解。
2、请求参数有误
这两种情况都非常广泛。
确定问题原因
尝试比较一下成功的请求和失败的请求有什么不同。比较400和200的请求,我们发现一个规律。我们观察到,从返回200状态码的请求的URL路径中并没有携带Host地址,类似于这样
>GET /svc/request HTTP/1.1
Host: sample1.com
HTTP/1.1 200
但当URL路径携带了完整的Host地址时,请求进入新应用就会返回400状态码
GET http://sample1.com:80/svc/request HTTP/1.1
Host: sample1.com
HTTP/1.1 400
可以看到以上两个请求中,请求头中都有Host字段,并传入的都是正确的值。然而这个时候,我们发现了一个细节,在返回状态码为400的请求中,请求头Host中的值是不带“:80”端口信息的,但在URL路径中,Host则携带了端口号。
那么有没有可能是URL路径和Request Header中Host不匹配造成的400状态码呢?我们将两者统一了之后再进行尝试,发现无论是否携带端口,只要两者是一致的,就能请求成功。
GET http://sample1.com:80/svc/request HTTP/1.1
Host: sample1bc.com:80
HTTP/1.1 200
GET http://sample1.com/svc/request HTTP/1.1
Host: sample1.com
HTTP/1.1 200
那么我们基本上可以确定,返回400状态码的请求都是URL路径与请求头的Host不一致的。那接下来的问题是,这些URL和Header中Host不一致的请求是新出现的还是原本就有的呢?如果原本就有,那么为什么应用服务器升级前没出现同样的问题呢?
通过查询规范,HTTP1.1 RFC2616规定 Header Host的值和URI的Host值可以不一样,请参考3.2.3章 《URI Comparison》。HTTP1.1 RFC7230则严格不允许,请参考5.5章 《Effective Request URI》。
于是我们查看了旧版本的应用服务器,发现它使用的是较为早期的RFC2616协议,而新应用服务器则使用的是RFC7230协议。
对于RFC 2616和RFC 7230的实现,我们可以参考开源项目Tomcat的源码中的Http11Processor类中的部分代码。
// The requirements of RFC 2616 are being
// applied. If the host header and the request
// line do not agree, the request line takes
// precedence
hostValueMB headers.setValueC'host");
hostValueMB.setBytes(uriB, uriBCStart + pos, slashPos pos);
} else {
// The requirements of RFC 7230 are being
// applied. If the host header and the request
// line do not agree, trigger a 400 response.
response.setStatus(400);
setErrorState(Errorstate.CLOSE_CLEAN, null);
if (log.isDebugEnabled()) {
log,debug(sm.getString("httpllprocessor. request. inconsistentHosts'*)); }
}
}
从代码中很容易就可以看出两种协议的不同实现,RFC2616会忽略请求头中原有的字段,将URL路径中的Host放到请求头的字段中。而RFC7230严格不允许Header与URL中的Host不匹配,则会返回400的状态码。源码中protocol.getAllowHostHeaderMismatch()默认值即为false,说明Tomcat实现的是RFC7230协议。
原理了解清楚了之后,解决方法自然就明确了。RFC7230协议强校验Host不一致一定有它的历史原因,那么理论上请求都应该遵循RFC7230的规范。那么要使URL中的Host和Header中的Host一致,我们可以在客户端修改,也可以在路由中进行修改。修改后,这个问题就被完美解决了。
标签:HTTP,请求,url,URL,错误码,Header,Host,400,com From: https://www.cnblogs.com/JacketLi/p/17088040.html