1.场景分析

最近有个需求,有个功能只能让外网用户使用,内网用户无感,并且是在同一个引用中,那么我就需要在初始化的时候,对当前用户的IP进行判断,看看这个IP是否可以访问内网

2.前端实现

前端实现就一个思路,用AJAX调用一个只有内网可以访问的到的数据或者接口。如果超时了,那么就是外网。

//代码主体
ping = (address,callback) =>{
  var img = new Image();
  var start = new Date().getTime();
  //一张内网图片 用来判断网络类型 外网是加载不到这个图片的
  img.src =address+"?time="+start;
  var flag = false;
  img.onload = function(){
    flag = true;
    //在2秒内 加载出图片 那么就认定为是内网
    console.log("内网网络")
  }
  var timer = setTimeout(function(){
      if(!flag){
        flag = false;
        if (callback && typeof callback == 'function') callback();
      }
  },2000);
}
//使用回调函数触发我们的事件
 this.ping("http://neiwang.com/static/img/4345wee68dsfsd.png",()=>{ 
  //只有外网才会执行这个回调
  alert("我是外网")
})

代码很简单,只要在定时器到达之前响应我们信息,那就是内网,但是存在一个很严重的风险
假如用来校验内网的那个资源被删了或者接口挂了,那么我们的全部IP都会视为外网,因为你统统都超时了。或者假如我们网络震荡,或者加载的资源很大,也会造成问题。所以想用这个办法一定要保证,用来校验的资源或者接口一定要很快,资源保证不会被误删。最好专门写一个接口或者一个小图片来做接口超时的判断。不要随便哪一个好几十M的图片,万一网络炸了就完蛋了。

3.后端实现

public static boolean test() throws IOException {
        String ip = "apaddress";
        Runtime runtime = Runtime.getRuntime(); // 获取当前程序的运行进对象
        Process process = null; //声明处理类对象
        String line = null; //返回行信息
        InputStream is = null; //输入流
        InputStreamReader isr = null;// 字节流
        BufferedReader br = null;
        boolean res = false;// 结果
        try {
            process = runtime.exec("ping " + ip); // PING
            is = process.getInputStream(); // 实例化输入流
            isr = new InputStreamReader(is);// 把输入流转换成字节流
            br = new BufferedReader(isr);// 从字节中读取文本
            while ((line = br.readLine()) != null) {
            	//这里一定要转大写 因为在linux系统中,是小写的 要兼容系统就加上
                if (line.toUpperCase().contains("TTL")) {
                    res = true;
                    break;
                }
            }
            if (res) {
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            runtime.exit(1);
            return false;
        } finally {
            if (is != null) {
                is.close();
            }
            if (isr != null) {
                isr.close();
            }
            if (br != null) {
                br.close();
            }
        }
    }

我个人更加倾向于用后端去实现,这个只需要使用IP即可,无需其他资源,更加安全。

4.注意事项

如果使用后端方式的小伙伴注意,因为java模拟PING请求,如果通不了的话可能会造成长时间的卡顿,因为获取请求的方式是while循环,存在卡顿的情况。所以在调用这个接口的时候,ajax一定要加上超时时间。避免无线等待造成其他问题。
参考代码如下:

ipAddressPing = (ip,callback,timeout=2000)=>{
    $.ajax({
      url:'/api/demo/ipAddressPing?ipAddress='+ip,
      type:'get',
      timeout:timeout, //设置超时的时间2s
      success:function(res){
        console.log(res)
        //请求没超时,但是PING不通,也说明是外网 需要调用接口 这里具体的你们自行判断
        if (!res) { 
          if (callback && typeof callback == 'function') callback(res);
        }
      },
      error:function(err){
        console.log(err)
        //请求超时说明 外网 需要调用接口
        if (callback && typeof callback == 'function') callback(res);
      }
    })
  }