Python -- 连接错误:超过最大重试次数
我有时候会遇到这样一个错误,当我的一个服务器(我们叫它服务器A)向另一个服务器(我们叫它服务器B)请求资源时,会出现这个错误:
ConnectionError: HTTPConnectionPool(host='some_ip', port=some_port): 最大重试次数超过,网址: /some_url/ (原因: [Errno 111] 连接被拒绝)
这个错误信息中提到的内容是:
message : None: 最大重试次数超过,网址: /some_url/ (原因: 重定向)
我提到这个是因为它包含了额外的信息 (原因: 重定向)
。
正如我所说,我控制着这两个服务器,所以我可以对其中一个或两个都进行修改。而且,这个错误似乎是偶尔出现的,并不是每次都会发生。
可能相关的信息是——服务器A是一个运行Apache的Python服务器,而服务器B是一个NodeJS服务器。我并不是一个网络服务器的高手,所以除了这些,我不太确定还有什么信息是相关的。
有没有人知道这个错误到底是什么意思,或者该如何调查解决方案?或者,有人知道哪个服务器可能是问题所在,是发起请求的那个,还是接收请求的那个?
编辑:这个错误也开始出现在我们对外部网络资源的调用中。
3 个回答
这看起来像是Node端的重定向循环。
你提到的服务器B是Node服务器,如果你设置路由时不小心,可能会造成重定向循环。比如说,如果你在服务器B上使用express,你可能会有两个路由,假设你把路由逻辑放在一个单独的模块里:
var routes = require(__dirname + '/routes/router')(app);
//... express setup stuff like app.use & app.configure
app.post('/apicall1', routes.apicall1);
app.post('/apicall2', routes.apicall2);
那么你的routes/router.js可能看起来像这样:
module.exports = Routes;
function Routes(app){
var self = this;
if (!(self instanceof Routes)) return new Routes(app);
//... do stuff with app if you like
}
Routes.prototype.apicall1 = function(req, res){
res.redirect('/apicall2');
}
Routes.prototype.apicall2 = function(req, res){
res.redirect('/apicall1');
}
这个例子很明显,但在这些路由中的一些条件里,可能会隐藏着重定向循环。我建议你先检查一些边缘情况,比如在相关路由的条件结束时会发生什么,如果请求没有正确的参数,默认行为是什么,以及异常情况下的行为是什么?
另外,你可以使用像node-validator这样的工具(https://github.com/chriso/node-validator)来帮助判断和处理错误的请求或提交参数。
// Inside router/routes.js:
var check = require('validator').check;
function Routes(app){ /* setup stuff */ }
Routes.prototype.apicall1 = function(req, res){
try{
check(req.params.csrftoken, 'Invalid CSRF').len(6,255);
// Handle it here, invoke appropriate business logic or model,
// or redirect, but be careful! res.redirect('/secure/apicall2');
}catch(e){
//Here you could Log the error, but don't accidentally create a redirect loop
// send appropriate response instead
res.send(401);
}
}
为了帮助判断是否是重定向循环,你可以做几件事。你可以使用curl命令来请求带有相同提交参数的URL(假设这是一个POST请求,否则你可以直接用Chrome浏览器,如果发现重定向循环,它会在控制台报错),或者你可以在Node服务器上输出到标准输出,或者在出问题的路由中写入系统日志。
希望这些能帮到你,提到“由于重定向引起”的部分真是个好主意,我觉得这就是问题所在。
上面的例子使用express来描述情况,但其实这个问题也可能出现在使用connect、其他框架,甚至是你自己写的处理代码时,如果你根本没有使用任何框架或库的话。无论如何,我建议养成良好的参数检查习惯,并且总是测试你的边缘情况,我过去在赶时间时就遇到过这个问题。
如果你在你的Python服务器上使用gevent,可能需要升级一下版本。看起来gevent在处理DNS解析时有一些小问题。
这是关于requests库的讨论:https://github.com/kennethreitz/requests/issues/1202#issuecomment-13881265
你在连接某个IP和端口时遇到了“连接被拒绝”的问题。这可能是因为: - 没有服务器在那个IP和端口上监听 - 防火墙设置导致连接被拒绝(这种情况不太常见) - 服务器配置错误(这种情况更常见)或者服务器忙,无法处理请求。
我认为,当服务器A试图连接服务器B时,你会遇到这个错误。(假设你使用的是Linux或类似Unix的系统)你可以在服务器上运行命令`netstat -ln -tcp`,看看结果是什么。(可以查一下`man netstat`来了解这些参数的意思——我们在这里的目的是找出哪些程序在监听哪些端口)。如果结果显示服务器B确实在监听,那么接下来可以用`iptables -L -n`来查看防火墙规则。如果这里没有问题,那很可能是监听队列的配置有问题。(你可以查看这个链接,或者在网上搜索“listen backlog”。)
这很可能是你服务器B的配置问题。(注意:如果有人提到的重定向循环处理不当,可能会导致服务器忙碌!解决这个问题也许能解决你的问题。)