const axios = require('axios') const request = axios.create({ timeout: 3000 }) // 为空时请求本地IP const getNetIPInfo = async (searchIp = '') => { searchIp = searchIp.replace(/::ffff:/g, '') || '' // fix: nginx反代 if(['::ffff:', '::1'].includes(searchIp)) searchIp = '127.0.0.1' try { let date = Date.now() let ipUrls = [ // 45次/分钟&支持中文(无限制) `http://ip-api.com/json/${ searchIp }?lang=zh-CN`, // 10000次/月&支持中文(依赖IP计算调用次数) `http://ipwho.is/${ searchIp }?lang=zh-CN`, // 1500次/天(依赖密钥, 超出自行注册) `https://api.ipdata.co/${ searchIp }?api-key=c6d4d04d5f11f2cd0839ee03c47c58621d74e361c945b5c1b4f668f3`, // 50000/月(依赖密钥, 超出自行注册) `https://ipinfo.io/${ searchIp }/json?token=41c48b54f6d78f`, // 1000次/天(依赖密钥, 超出自行注册) `https://api.ipgeolocation.io/ipgeo?apiKey=105fc2c7e8864ec08b98e1ad4e8cbc6d&ip=${ searchIp }`, // 1000次/天(依赖IP计算调用次数) `https://ipapi.co${ searchIp ? `/${ searchIp }` : '' }/json`, // 国内IP138提供(无限制) `https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=${ searchIp }&resource_id=5809` ] let result = await Promise.allSettled(ipUrls.map(url => request.get(url))) let [ipApi, ipwho, ipdata, ipinfo, ipgeolocation, ipApi01, ip138] = result let searchResult = [] if(ipApi.status === 'fulfilled') { let { query: ip, country, regionName, city } = ipApi.value?.data || {} searchResult.push({ ip, country, city: `${ regionName } ${ city }`, date }) } if(ipwho.status === 'fulfilled') { let { ip, country, region: regionName, city } = ipwho.value?.data || {} searchResult.push({ ip, country, city: `${ regionName } ${ city }`, date }) } if(ipdata.status === 'fulfilled') { let { ip, country_name: country, region: regionName, city } = ipdata.value?.data || {} searchResult.push({ ip, country, city: `${ regionName } ${ city }`, date }) } if(ipinfo.status === 'fulfilled') { let { ip, country, region: regionName, city } = ipinfo.value?.data || {} searchResult.push({ ip, country, city: `${ regionName } ${ city }`, date }) } if(ipgeolocation.status === 'fulfilled') { let { ip, country_name: country, state_prov: regionName, city } = ipgeolocation.value?.data || {} searchResult.push({ ip, country, city: `${ regionName } ${ city }`, date }) } if(ipApi01.status === 'fulfilled') { let { ip, country_name: country, region: regionName, city } = ipApi01.value?.data || {} searchResult.push({ ip, country, city: `${ regionName } ${ city }`, date }) } if(ip138.status === 'fulfilled') { let [res] = ip138.value?.data?.data || [] let { origip: ip, location: country, city = '', regionName = '' } = res || {} searchResult.push({ ip, country, city: `${ regionName } ${ city }`, date }) } // console.log(searchResult) let validInfo = searchResult.find(item => Boolean(item.country)) consola.info('查询IP信息:', validInfo) return validInfo || { ip: '获取IP信息API出错,请排查或更新API', country: '未知', city: '未知', date } } catch (error) { consola.error('getIpInfo Error: ', error) return { ip: '未知', country: '未知', city: '未知', error } } } const throwError = ({ status = 500, msg = 'defalut error' } = {}) => { const err = new Error(msg) err.status = status // 主动抛错 throw err } const isIP = (ip = '') => { const isIPv4 = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/ const isIPv6 = /^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}|:((:[\da−fA−F]1,4)1,6|:)|:((:[\da−fA−F]1,4)1,6|:)|^[\da-fA-F]{1,4}:((:[\da-fA-F]{1,4}){1,5}|:)|([\da−fA−F]1,4:)2((:[\da−fA−F]1,4)1,4|:)|([\da−fA−F]1,4:)2((:[\da−fA−F]1,4)1,4|:)|^([\da-fA-F]{1,4}:){3}((:[\da-fA-F]{1,4}){1,3}|:)|([\da−fA−F]1,4:)4((:[\da−fA−F]1,4)1,2|:)|([\da−fA−F]1,4:)4((:[\da−fA−F]1,4)1,2|:)|^([\da-fA-F]{1,4}:){5}:([\da-fA-F]{1,4})?|([\da−fA−F]1,4:)6:|([\da−fA−F]1,4:)6:/ return isIPv4.test(ip) || isIPv6.test(ip) } const randomStr = (len) =>{ len = len || 16 let str = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678', a = str.length, res = '' for (let i = 0; i < len; i++) res += str.charAt(Math.floor(Math.random() * a)) return res } // 获取UTC-x时间 const getUTCDate = (num = 8) => { let date = new Date() let now_utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours() + num, date.getUTCMinutes(), date.getUTCSeconds()) return new Date(now_utc) } const formatTimestamp = (timestamp = Date.now(), format = 'time') => { if(typeof(timestamp) !== 'number') return '--' let date = new Date(timestamp) let padZero = (num) => String(num).padStart(2, '0') let year = date.getFullYear() let mounth = padZero(date.getMonth() + 1) let day = padZero(date.getDate()) let hours = padZero(date.getHours()) let minute = padZero(date.getMinutes()) let second = padZero(date.getSeconds()) let weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六' ] let week = weekday[date.getDay()] switch (format) { case 'date': return `${ year }-${ mounth }-${ day }` case 'week': return `${ year }-${ mounth }-${ day } ${ week }` case 'hour': return `${ year }-${ mounth }-${ day } ${ hours }` case 'time': return `${ year }-${ mounth }-${ day } ${ hours }:${ minute }:${ second }` default: return `${ year }-${ mounth }-${ day } ${ hours }:${ minute }:${ second }` } } module.exports = { getNetIPInfo, throwError, isIP, randomStr, getUTCDate, formatTimestamp }