fastdfs
fastdfs copied to clipboard
使用https端口立即访问上传后的图片,出现400 bad request。
一、软件版本 Fastdfs版本:V6.07 Nginx版本:V1.20.0 Fastdfs-nginx-module 版本:V1.22
二、问题现象 生产线部署fastdfs文件服务器集群2台,同一个group,互相备份。在前端端上传文件后,在前端模块展示文件地址出错,展示信息为:400 bad request The plain HTTP request was sent to HTTPS port。过了1-2s后,重新访问返回的地址,恢复正常。
三、问题分析 出现这个问题后,首先想到的是前端预览插件访问文件时是否将https头替换成了http,导致400错误。于是让前端做了个功能,后端返回成功后,立即打开新页面访问,结果还是出现同样的400错误,于是排除前端访问协议头不正确的可能。 接下来就进行了服务器问题排查,由于我们部署了两台fastdfs机器,将两台机器上nginx的访问日志access.log拉下来后,发现访问文件的get请求同时出现在两台服务器的access.log上,两个状态码均是400。
两个日志进行对比,首先发现的就是后者带了redirect,前者没有。熟悉fastdfs的同学可能知道,fastdfs是一个高可用的文件存储访问系统,这边的redirect正是fastdfs-nginx模块访问文件的策略,当请求打到同一个group的某一台机器上时,fastdfs-nginx-首先会从本地路径去找文件,当找不到时,会进行请求转发,这个转发有两种模式,配置在mod_fastdfs.conf,默认是proxy,如图上注释所说:当请求的内容不在本地服务上时,将请求转发给同组的其它服务。
因此,大概猜想到了400bad request的原因为,当一个请求打到groupX的A机器上时,由于文件是刚刚才上传,A机器还没来得及从同组的B机器同步,故将请求转发给了B机器,但是重点来了,我们访问A机器时使用的是https协议+443端口,但是A机器转发请求时,却变成了http协议+443端口。由于B机器上nginx监听的443端口需要有ssl协议,此时就会报错:400 bad request The plain HTTP request was sent to HTTPS port。
四、源码定位 问题算是找到了,但是具体是哪一步处理问题?我们知道,fastdfs的作者开发了fastdfs-nginx-module,目的就是为了使用nginx来进行文件访问,于是我们从fastdfs-nginx-module模块的源码入手,进行原因分析,期待能把问题进行解决。
我们打开fastdfs-nginx-module文件夹,内容如上。我们通过上面access.log日志中的redirect参数可知,这个参数大概率是上面这些文件中的某一个产生的,通过一番检索,将目标定位在了common.c 文件的1173行。我们可以从这断代码中看到redirect_url的值,前面的http://是写死在代码里面的,但是端口却是取的port_part变量。
通过代码可以得知port_part参数是从nginx传递过来的,即为我们访问第一台nginx服务器的https端口,由此,上述代码将http协议和ssl端口进行了结合,然后进行访问,因此出现了400 bad request异常。看到这算是找到原因了,http协议+ssl端口。
五、问题解决 如果要进行解决,协议头和端口两者要么同时从nginx透传,要么将转发的端口进行配置,从配置文件中获取,此处不做展开。这里重点说下我们最终解决这个问题的办法,由于不管是把http改为https,还是将端口由ssl端口改为从配置文件中获取普通端口,虽然改动量不大,但都要进行代码改造和nginx重新make,相对来说比较麻烦。不妨我们换种思路,既然上述代码中写死了http,那我们为何不在请求进来时,就保障我们访问的是http端口。基于此种思路,我们在nginx上配置了两个端口,分别是443和80。443端口负责监听外部的ssl请求,当文件访问请求来临时,我们将请求转发到自己的80端口,这样从入口处我们就保障了请求是http协议,这样不管怎么转发,都不会出现http协议+ssl端口的问题。
我的集群也遇到了这个问题,我的环境是小程序,比较特殊,不能使用80端口,解决办法是在fastdfs上面再加一层nginx,将group[0-9]的流量转发至fastdfs所在的nginx。这样透传的转发地址就变成了http协议+80端口,就解决这个问题了。
抱歉我这边已经没有权限看到nginx配置了,大概说一下思路吧
“ 分析下来主要原因是,图片刚上传完,各个storage需要一点时间进行数据同步。请求的时候如果第一个storage没有找到图片,fastdfs会尝试去下一个storage进行寻找,寻找的方式就是拼接一个新的url请求。 问题就在拼接的这个新请求地址上,他的拼接逻辑是http协议+你的原始请求方式的端口。所以在我们的日志中就看到了请求10.141.133.52:443 这种http协议+ssl端口的奇怪请求方式,自然无法完成请求。 我们认为这是一个逻辑bug,我们选择在fastdfs前面再加一层业务nginx。最终实现的链路效果就是:用户的https图片请求---->业务nginx----->fastdfs的nginx。 也就是说将请求地址中带group[0-9]的请求,全部转发至下一层的nginx。这样fastdfs在拼接重定向url的时候地址就是http协议+80端口 ”
wshuigao @.***> 于2022年12月3日周六 20:56写道:
我的集群也遇到了这个问题,我的环境是小程序,比较特殊,不能使用80端口,解决办法是在fastdfs上面再加一层nginx,将group[0-9]的流量转发至fastdfs所在的nginx。这样透传的转发地址就变成了http协议+80端口,就解决这个问题了。
大佬,可以贴一下nginx那块相关配置吗,我没理解fastdfs上面再加一层nginx 是怎么回事
— Reply to this email directly, view it on GitHub https://github.com/happyfish100/fastdfs/issues/561#issuecomment-1336155326, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANQLXAMYDIEZDJ5YYBFE33LWLM7PPANCNFSM5WUG27QA . You are receiving this because you commented.Message ID: @.***>
抱歉我这边已经没有权限看到nginx配置了,大概说一下思路吧 “ 分析下来主要原因是,图片刚上传完,各个storage需要一点时间进行数据同步。请求的时候如果第一个storage没有找到图片,fastdfs会尝试去下一个storage进行寻找,寻找的方式就是拼接一个新的url请求。 问题就在拼接的这个新请求地址上,他的拼接逻辑是http协议+你的原始请求方式的端口。所以在我们的日志中就看到了请求10.141.133.52:443 这种http协议+ssl端口的奇怪请求方式,自然无法完成请求。 我们认为这是一个逻辑bug,我们选择在fastdfs前面再加一层业务nginx。最终实现的链路效果就是:用户的https图片请求---->业务nginx----->fastdfs的nginx。 也就是说将请求地址中带group[0-9]的请求,全部转发至下一层的nginx。这样fastdfs在拼接重定向url的时候地址就是http协议+80端口 ” wshuigao @.> 于2022年12月3日周六 20:56写道: … 我的集群也遇到了这个问题,我的环境是小程序,比较特殊,不能使用80端口,解决办法是在fastdfs上面再加一层nginx,将group[0-9]的流量转发至fastdfs所在的nginx。这样透传的转发地址就变成了http协议+80端口,就解决这个问题了。 大佬,可以贴一下nginx那块相关配置吗,我没理解fastdfs上面再加一层nginx 是怎么回事 — Reply to this email directly, view it on GitHub <#561 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANQLXAMYDIEZDJ5YYBFE33LWLM7PPANCNFSM5WUG27QA . You are receiving this because you commented.Message ID: @.>
好的,谢谢老哥
我也遇到这个问题了