最近想写个B/S架构的聊天系统,因为以前做过C/S架构的QQ聊天系统,所以对于Socket通信编程只是一个巩固。对于C/S架构的聊天系统,由于存在客户端Java应用,所以直接在代码中获取客户端的IP,应用的方法为:
String ip = InetAddress.getLocalHost().getHostAddress();
然而对于WEB系统来说,客户端只是一个浏览器,怎么才能获取用户的IP呢,而且又要分内网环境和外网环境两种。
内网环境:
聊天系统用于内网的话,我首先想到了通过JS来实现获取用户的IP,确实也有方法可以支持:
//通过js获得客户端IP,这里获取的IP是本机所有的IP(包括内网和外网)
function GetLocalIPAddr(){
var oSetting = null;
var ip = null;
try{
oSetting = new ActiveXObject("rcbdyctl.Setting");
ip = oSetting.GetIPAddress;
if (ip.length == 0){
return "没有连接到Internet";
}
oSetting = null;
}catch(e){
return ip;
}
return ip;
}
不过此方法只支持IE浏览器,我不得不加了个判断浏览器类别的方法:
//首先判断客户端的浏览器情况
$(function(){
if($.browser.msie){
clientIP = GetLocalIPAddr();
$("#showMessage").html("您的IP为:"+dealWith(clientIP));
sendMessageToServlet("busi=connect&connectIP="+dealWith(clientIP));
}else if($.browser.opera){
//alert("这是一个opera浏览器!");
$("#showMessage").html("建议您使用IE浏览器,否则要手动输入IP!");
}else if($.browser.mozilla){
//alert("这是一个mozilla浏览器!");
$("#showMessage").html("建议您使用IE浏览器,否则要手动输入IP!");
}else if($.browser.safa){
//alert("这是一个safa浏览器!");
$("#showMessage").html("建议您使用IE浏览器,否则要手动输入IP!");
}
});
怎么才能完整的获取客户端的IP呢?(如果有哪位朋友做过,期望指点一下啊,交个朋友,呵呵)
外网环境:
我们这边在做的网上营业厅系统中有获取用户外网IP的方法,实现方法:
public static String getCurrentIP(HttpServletRequest request){
String result = "";
if (result == null || result.length() == 0
|| "unknown".equalsIgnoreCase(result)) {
result = request.getHeader("x-forwarded-for");
}
if (result == null || result.length() == 0
|| "unknown".equalsIgnoreCase(result)) {
result = request.getHeader("X-Forwarded-For");
}
if (result == null || result.length() == 0
|| "unknown".equalsIgnoreCase(result)) {
result = request.getHeader("Proxy-Client-IP");
}
if (result == null || result.length() == 0
|| "unknown".equalsIgnoreCase(result)) {
result = request.getHeader("WL-Proxy-Client-IP");
}
if (result == null || result.length() == 0
|| "unknown".equalsIgnoreCase(result)) {
result = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (!StringUtils.isEmpty(result)) {
if (result.indexOf(".") != -1){ // 没有"."肯定是非IPv4格式
Pattern pat = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
Matcher mat = pat.matcher(result);
result = null;
while (mat.find()) {
result = mat.group(0);
break;
}
}
else
result = null;
}
下面是网上广为流传的解释:
在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。
如果使用了反向代理软件,将http://192.168.1.110 :2046/ 的URL反向代理为 http://www.xxx.cn / 的URL时,用request.getRemoteAddr()方法获取的IP地址是:127.0.0.1 或 192.168.1.110,而并不是客户端的真实IP。
经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器 无法直接拿到客户端的IP,服务器 端应用也无法直接通过转发请求的地址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器地址。当我们访问http://www.5555.cn /index.jsp/ 时,其实并不是我们浏览器真正访问到了服务器上的index.jsp文件,而是先由代理服务器去访问http://192.168.1.110 :2046/index.jsp ,代理服务器再将访问到的结果返回给我们的浏览器,因为是代理服务器去访问index.jsp的,所以index.jsp中通过 request.getRemoteAddr()的方法获取的IP实际上是代理服务器的地址,并不是客户端的IP地址。
public String getRemortIP(HttpServletRequest request) {
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
return request.getHeader("x-forwarded-for");
}
可是当我访问http://www.5555.cn /index.jsp/ 时,返回的IP地址始终是unknown,也并不是如上所示的127.0.0.1 或 192.168.1.110了,而我访问http://192.168.1.110 :2046/index.jsp 时,则能返回客户端的真实IP地址,写了个方法去验证。原因出在了Squid上。squid.conf 的配制文件 forwarded_for 项默认是为on,如果 forwarded_for 设成了 off 则:X-Forwarded-For: unknown
于是可得出获得客户端真实IP地址的方法二:
public String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串Ip值,究竟哪个才是真正的用户端的真实IP呢?
答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100用户真实IP为: 192.168.1.110