问题:vue项目中需要获取用户的IPV4并传给后端

一、内网

1.在vue中我们可用借用node.js获取IPv4

在 【config/index.js】 中

const os = require('os');
 
function getNetworkIp() {  //获取当前IP地址
	let needHost = ''; // 打开的host
	try {
		// 获得网络接口列表
		let network = os.networkInterfaces();
		for (let dev in network) {
			let iface = network[dev];
			for (let i = 0; i < iface.length; i++) {
				let alias = iface[i];
				if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
					needHost = alias.address;
				}
			}
		}
	} catch (e) {
        console.log("*",e);
		needHost = '127.0.0.1';
	}
	return needHost;
}

但此方法有一个问题。在 node 环境中我们使用不了 window,无法将它保存到 sessionStorage 里去,所以

module.exports = {
  dev: {
    // ...
    host: getNetworkIp(),
    // ...
  }
}

在需要的地方调用  window.location.host

那么问题又来了,我们是从路径上截取到的ipv4。也就是说当我使用 127.0.0.1 或者 localhost 登录时,这ipv4就不对了,如果部署上线的话...

参考文献:https://dongkelun.com/2019/03/28/vueAutoIp...

2. js/vue 获取本地ipv4

法一:

function getLocalIPv4(){  //获取本机IPv4
  if(typeof window != 'undefined'){
    var RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;

    if (RTCPeerConnection) (()=>{
      var rtc = new RTCPeerConnection()
      rtc.createDataChannel(''); //创建一个可以发送任意数据的数据通道
      rtc.createOffer( offerDesc => { //创建并存储一个sdp数据
        rtc.setLocalDescription(offerDesc)
      }, e => { console.log(e)})

      rtc.onicecandidate =(evt) => { //监听candidate事件
        if (evt.candidate) {
          // console.log('evt:',evt.candidate)
          let ip_rule = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
          let ip_addr = ip_rule.exec(evt.candidate.candidate)
          if (ip_addr) {
            sessionStorage.setItem("ip",ip_addr[1])  // 保存 本机IP
          }
          // console.log('ip_addr:',ip_addr)   //打印获取的IP地址
        }
      }
    })()
    else{console.log("没有找到")}
  }
}
getLocalIPv4()

 法二:

function getUserIP(onNewIP) {
  let MyPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
  let pc = new MyPeerConnection({
    iceServers: []
  });
  let noop = () => {
  };
  let localIPs = {};
  let ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g;
  let iterateIP = (ip) => {
    if (!localIPs[ip]) onNewIP(ip);
    localIPs[ip] = true;
  };
  pc.createDataChannel('');
  pc.createOffer().then((sdp) => {
    sdp.sdp.split('\n').forEach(function (line) {
      if (line.indexOf('candidate') < 0) return;
      line.match(ipRegex).forEach(iterateIP);
    });
    pc.setLocalDescription(sdp, noop, noop);
  }).catch((reason) => {
  });
  pc.onicecandidate = (ice) => {
    if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;
    ice.candidate.candidate.match(ipRegex).forEach(iterateIP);
  };
}

getUserIP((ip) => {
    //注意:有的浏览器获取到的是IPv4地址,有的是IPv6地址 
    console.log("ip",ip);
})

 如果获取不到,可能是浏览器隐藏了ip

谷歌(Chrome) 删除隐藏IP

浏览器输入:chrome://flags/#enable-webrtc-hide-local-ips-with-mdns  把 Anonymize local IPs exposed by WebRTC 设置为 disabled ( 刷新程序,IP正常显示 )

火狐(FireFox) 删除隐藏IP

浏览器输入 about:config   搜索配置 media.peerconnection.enabled 改为false ( 刷新程序,IP正常显示 )

二、外网

如果是vue项目:在文件夹中 index.html 加如下代码:(注:此处使用的是搜狐接口)

<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script>
<script type="text/javascript">
    console.log(`您的ip是${returnCitySN.cip}您的所在地是${returnCitySN.cname}`);
    console.log(returnCitySN);
    sessionStorage.setItem('cip', returnCitySN["cip"])  // 保存cip地址
</script>

三、讨论

2023/7/10 --- 新增

是的,在开发过程中,我们不可能要求每一位用户给自己的浏览器开放ip权限。

而【config/index.js】文件又处于node环境中,没有Windows对象也没有vue环境,所以我想到了另一种方式将ip传给vue--跨域

1.在【vue.config.js】文件中配置跨域

const { defineConfig } = require('@vue/cli-service')

const os = require('os');
 
function getNetworkIp() {  //获取当前IP地址
	let needHost = ''; // 打开的host
	try {
		// 获得网络接口列表
		let network = os.networkInterfaces();
		for (let dev in network) {
			let iface = network[dev];
			for (let i = 0; i < iface.length; i++) {
				let alias = iface[i];
				if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
					needHost = alias.address;
				}
			}
		}
	} catch (e) {
        console.log("*",e);
		needHost = '127.0.0.1';
	}
	return needHost;
}

module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    proxy: {
      '/api': {
        // 配置其他跨域
      },
        // 获取ipv4
      '/getIP': {
        target: 'http://' + getNetworkIp(),
        ws: false,
        changeOrigin: true
      },
    }
  },
})

2.在其他页面调用

因为我们代理目标的基础路径不存在,所以它是一定会报错的。而ip就藏在这错误信息中,最好再用Axios拦截器(Interceptors)统一格式。

<script>
import axios from "axios"
export default {
 
  mounted () {
    axios.get("http://localhost:8080/getIP")
    .catch(e=>{
      console.log(e.response.data);
    })
  }
}
</script>

3.查看控制台打印

 接下来只需要字符串截取一下就能拿到ipv4了。

2023/7/11 --- 新增

4. 测试

在本机上测试是没有问题的,但是当我换了台电脑测时,发现跨域的错误信息中缺少了一个关键的参数 response

既然在前端不放便将获取到的ip传给vue,那么我想到了后端。我们先以 查询字符串 的形式将ip传给后端,再由后端返回如何?当然,如果后端能直接获取到客户端ip地址,这就有点...多次一举了。

配置跨域:

proxy: {
    '/getIP': {
        target: `http://localhost:3000/ip` // 服务器请求地址
			+`?ip=`+ getNetworkIp(),  // 查询字符串
        ws: false,
        changeOrigin: true,
    },
}

控制台打印:

 

如果你有什么意见或者建议也欢迎给我留言,谢谢。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐