文章背景
笔者在公司做一个项目, 在测试环境功能一切正常,但是上线后发现竟然连登录都异常了。观察日志,发现是没有从redis取到登录的随机密钥。我的项目登录分为两步,前端向后端请求随机密钥,后端将这个随机密钥以ip为唯一标识存到redis中并返回给前端,前端根据密钥加密登录数据然后请求登录,随机密钥虽然生成了并set了进redis,但是取的时候却出错了,每次取出来的密钥都为null
。
问题原因
观察日志信息,发现获取的请求方ip地址有问题。原来是因为做了nginx反向代理的缘故。我之前获取ip地址只是简单的通过HttpServletRequest
的request.getRemoteAddr()
方法来获取,但是在nginx反向代理的情况下,这个方法只能获取到nginx代理服务器的ip地址。且由于做了负载均衡,代理的服务器有多个,所以无法使用前端请求登录的时对应的ip地址获取到登录密钥。
request.getRemoteAddr()
这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。
解决办法
经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器无法直接拿到客户端的ip,服务器端应用也无法直接通过转发请求的地址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR
信息。用以跟踪原有的客户端ip地址和原来客户端请求的服务器地址。因此,可以利用这个请求头字段来获取ip地址。
public static String getRemortIP(HttpServletRequest request) {
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
return request.getHeader("x-forwarded-for");
}
对于更复杂的多重代理,也有对应的解决办法。
网友评论