# 离线IP库 **Repository Path**: Super_TongYao/offline-ip-library ## Basic Information - **Project Name**: 离线IP库 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-07-31 - **Last Updated**: 2025-07-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 描述 本文实现: 1、离线查询IP地址 2、IP地址精确到区域 3、IP地址支持国外IP 此时需要一个创建,比如我输入一个8.8.8.8的IP立马就需要返回给我一个中文地址信息, 类似于百度的IP搜索: ``` 113.111.186.123 ``` ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/9a43e7ee8e4e45568a0567329f0fc3ee.png) 如果现在离线环境或者在线环境上本地部署一套IP地址查询,可以查阅本文章。 本文本地部署的结果演示(`注意!本文演示的项目不包含任何一个在线API接口!!!`): ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0c00ab305d934c19ab5032521688d280.png) 首先感谢GItHub地址:https://github.com/ljxi/GeoCN 作者的在线演示地址: ``` https://ipv4.netart.cn/ https://ipv4.netart.cn/113.111.186.123 ``` 这个仓库是用的Python 的 Fast API 开发的,此时我需要一个Java的,本文会有Java的项目地址。 ---------------------------------------------------------------------------------------- 还有一种技术,只有springboot的,返回数据不是准确,感兴趣的可以自己去看看: ip2region仓库地址:[https://gitee.com/lionsoul/ip2region](https://gitee.com/lionsoul/ip2region) ip2region集成文章:[https://cloud.tencent.com/developer/article/2373096](https://cloud.tencent.com/developer/article/2373096) ---------------------------------------------------------------------------------------- ## 开始 1、下载IP库 mmdb 仓库:[https://github.com/P3TERX/GeoLite.mmdb/releases](https://github.com/P3TERX/GeoLite.mmdb/releases)(不主要) mmdb IP库下载:[https://github.com/P3TERX/GeoLite.mmdb/releases](https://github.com/P3TERX/GeoLite.mmdb/releases) 只需要下载以下两个mmdb文件 ``` GeoLite2-City.mmdb GeoLite2-ASN.mmdb ``` 如果你的网络出不了国,可以下载国内的:[https://download.csdn.net/download/u014641168/91554209](https://download.csdn.net/download/u014641168/91554209) 还需下载: ``` GeoCN.mmdb ``` 这个文件在作者的仓库中就能找到,地址:[https://github.com/ljxi/GeoCN/releases/tag/Latest](https://github.com/ljxi/GeoCN/releases/tag/Latest) 如果打不开,看国内:[https://download.csdn.net/download/u014641168/91554230](https://download.csdn.net/download/u014641168/91554230) (我忘了整合到一块,将就着看吧) ## 代码 ### python 首先作者的代码时Python的,Python版本是3.9的,需要手动安装插件库 ``` pip install ipaddress pip install maxminddb ``` 还有fastapi 1、代码如下: ``` import ipaddress import maxminddb from fastapi import FastAPI, Request city_reader = maxminddb.open_database('C:\\Users\\ad\\Desktop\\ip\\GeoLite2-City.mmdb') asn_reader = maxminddb.open_database('C:\\Users\\ad\\Desktop\\ip\\GeoLite2-ASN.mmdb') cn_reader = maxminddb.open_database('C:\\Users\\ad\\Desktop\\ip\\GeoCN.mmdb') lang = ["zh-CN","en"] asn_map = { 9812:"东方有线", 9389:"中国长城", 17962:"天威视讯", 17429:"歌华有线", 7497:"科技网", 24139:"华数", 9801:"中关村", 4538:"教育网", 24151:"CNNIC", 38019:"中国移动",139080:"中国移动",9808:"中国移动",24400:"中国移动",134810:"中国移动",24547:"中国移动", 56040:"中国移动",56041:"中国移动",56042:"中国移动",56044:"中国移动",132525:"中国移动",56046:"中国移动", 56047:"中国移动",56048:"中国移动",59257:"中国移动",24444:"中国移动", 24445:"中国移动",137872:"中国移动",9231:"中国移动",58453:"中国移动", 4134:"中国电信",4812:"中国电信",23724:"中国电信",136188:"中国电信",137693:"中国电信",17638:"中国电信", 140553:"中国电信",4847:"中国电信",140061:"中国电信",136195:"中国电信",17799:"中国电信",139018:"中国电信", 133776:"中国电信",58772:"中国电信",146966:"中国电信",63527:"中国电信",58539:"中国电信",58540:"中国电信", 141998:"中国电信",138169:"中国电信",139203:"中国电信",58563:"中国电信",137690:"中国电信",63838:"中国电信", 137694:"中国电信",137698:"中国电信",136167:"中国电信",148969:"中国电信",134764:"中国电信", 134770:"中国电信",148981:"中国电信",134774:"中国电信",136190:"中国电信",140647:"中国电信", 132225:"中国电信",140485:"中国电信",4811:"中国电信",131285:"中国电信",137689:"中国电信", 137692:"中国电信",140636:"中国电信",140638:"中国电信",140345:"中国电信",38283:"中国电信", 140292:"中国电信",140903:"中国电信",17897:"中国电信",134762:"中国电信",139019:"中国电信", 141739:"中国电信",141771:"中国电信",134419:"中国电信",140276:"中国电信",58542:"中国电信", 140278:"中国电信",139767:"中国电信",137688:"中国电信",137691:"中国电信",4809:"中国电信", 58466:"中国电信",137687:"中国电信",134756:"中国电信",134760:"中国电信", 133774:"中国电信",133775:"中国电信",4816:"中国电信",134768:"中国电信", 58461:"中国电信",58519:"中国电信",58520:"中国电信",131325:"中国电信", 4837:"中国联通",4808:"中国联通",134542:"中国联通",134543:"中国联通",10099:"中国联通", 140979:"中国联通",138421:"中国联通",17621:"中国联通",17622:"中国联通",17816:"中国联通", 140726:"中国联通",17623:"中国联通",136958:"中国联通",9929:"中国联通",58519:"中国联通", 140716:"中国联通",4847:"中国联通",136959:"中国联通",135061:"中国联通",139007:"中国联通", 59019:"金山云", 135377:"优刻云", 45062:"网易云", 137718:"火山引擎", 37963:"阿里云",45102:"阿里云国际", 45090:"腾讯云",132203:"腾讯云国际", 55967:"百度云",38365:"百度云", 58519:"华为云", 55990:"华为云",136907:"华为云", 4609:"澳門電訊", 134773:"珠江宽频", 1659:"台湾教育网", 8075:"微软云", 17421:"中华电信", 3462:"HiNet", 13335:"Cloudflare", 55960:"亚马逊云",14618:"亚马逊云",16509:"亚马逊云", 15169:"谷歌云",396982:"谷歌云",36492:"谷歌云", } def get_as_info(number): r = asn_map.get(number) if r: return r def get_des(d): for i in lang: if i in d['names']: return d['names'][i] return d['names']['en'] def get_country(d): r = get_des(d) if r in ["香港", "澳门", "台湾"]: return "中国" + r return r def province_match(s): arr=['内蒙古','黑龙江','河北','山西','吉林','辽宁','江苏','浙江','安徽','福建','江西','山东','河南','湖北','湖南','广东','海南','四川','贵州','云南','陕西','甘肃','青海','广西','西藏','宁夏','新疆','北京','天津','上海','重庆'] for i in arr: if i in s: return i return '' def de_duplicate(regions): regions = filter(bool,regions) ret = [] [ret.append(i) for i in regions if i not in ret] return ret def get_addr(ip, mask): network = ipaddress.ip_network(f"{ip}/{mask}", strict=False) first_ip = network.network_address return f"{first_ip}/{mask}" def get_maxmind(ip: str): ret = {"ip":ip} asn_info = asn_reader.get(ip) if asn_info: as_ = {"number":asn_info["autonomous_system_number"],"name":asn_info["autonomous_system_organization"]} info = get_as_info(as_["number"]) if info: as_["info"] = info ret["as"] = as_ city_info, prefix = city_reader.get_with_prefix_len(ip) ret["addr"] = get_addr(ip, prefix) if not city_info: return ret if "country" in city_info: country_code = city_info["country"]["iso_code"] country_name = get_country(city_info["country"]) ret["country"] = {"code":country_code,"name":country_name} if "registered_country" in city_info: registered_country_code = city_info["registered_country"]["iso_code"] ret["registered_country"] = {"code":registered_country_code,"name":get_country(city_info["registered_country"])} regions = [get_des(i) for i in city_info.get('subdivisions', [])] if "city" in city_info: c = get_des(city_info["city"]) if (not regions or c not in regions[-1])and c not in country_name: regions.append(c) regions = de_duplicate(regions) if regions: ret["regions"] = regions return ret def get_cn(ip:str, info={}): ret, prefix = cn_reader.get_with_prefix_len(ip) if not ret: return info["addr"] = get_addr(ip, prefix) regions = de_duplicate([ret["province"],ret["city"],ret["districts"]]) if regions: info["regions"] = regions info["regions_short"] = de_duplicate([province_match(ret["province"]),ret["city"].replace('市',''),ret["districts"]]) if "as" not in info: info["as"] = {} info["as"]["info"] = ret['isp'] if ret['net']: info["type"] = ret['net'] return ret def get_ip_info(ip): info = get_maxmind(ip) if "country" in info and info["country"]["code"] == "CN" and ("registered_country" not in info or info["registered_country"]["code"] == "CN"): get_cn(ip,info) return info def query(): while True: try: ip = input('IP: \t').strip() info = get_ip_info(ip) print(f"网段:\t{info['addr']}") if "as" in info: print(f"ISP:\t",end=' ') if "info" in info["as"]: print(info["as"]["info"],end=' ') else: print(info["as"]["name"],end=' ') if "type" in info: print(f"({info['type']})",end=' ') print(f"ASN{info['as']['number']}",end=' ') print(info['as']["name"]) if "registered_country" in info and ("country" not in info or info["country"]["code"] != info["registered_country"]["code"]): print(f"注册地:\t{info['registered_country']['name']}") if "country" in info: print(f"使用地:\t{info['country']['name']}") if "regions" in info: print(f"位置: \t{' '.join(info['regions'])}") except Exception as e: print(e) raise e finally: print("\n") app = FastAPI() @app.get("/") def api(request: Request, ip: str = None): if not ip: xff = request.headers.get("x-forwarded-for") if xff: ip = xff.split(",")[0] else: ip = request.headers.get("x-real-ip") or request.client.host return get_ip_info(ip.strip()) @app.get("/{ip}") def path_api(ip): return get_ip_info(ip) if __name__ == '__main__': query() import uvicorn uvicorn.run(app, host="0.0.0.0", port=8080, server_header=False, proxy_headers=True) ``` 2、启动 ``` uvicorn main:app --port 9000 --reload ``` 3、浏览器访问 ``` http://localhost:9000/113.111.186.123 ``` ### Java 作者的Python代码不满足我的需求,手动转成Java格式 我的jdk1.8,maven 3.6 1、引入依赖 ``` com.maxmind.db maxmind-db 2.1.0 ``` 2、代码类: ASInfo.java ``` import lombok.Data; /** * @author: tongyao * @since: 2025-07-31 09:32 */ @Data public class ASInfo { private Integer number; private String name; private String info; } ``` CountryInfo.java ``` import lombok.Data; /** * @author: tongyao * @since: 2025-07-31 09:32 */ @Data public class CountryInfo { private String code; private String name; } ``` GeoCNResponse.java ``` import lombok.Data; @Data public class GeoCNResponse { private String province; private String city; private String districts; private String isp; private String net; private int prefixLen; // 移除MaxMindDbConstructor注解 public GeoCNResponse( String province, String city, String districts, String isp, String net, int prefixLen ) { this.province = province; this.city = city; this.districts = districts; this.isp = isp; this.net = net; this.prefixLen = prefixLen; } } ``` IPInfo.java ``` import lombok.Data; import java.util.List; @Data public class IPInfo { private String ip; private String addr; private String error; private String type; private CountryInfo country; private CountryInfo registeredCountry; private List regions; private List regionsShort; private ASInfo as; } ``` GeoIPConfig.java ``` import com.maxmind.db.Reader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.File; import java.io.IOException; @Configuration public class GeoIPConfig { @Bean public Reader cityReader() throws IOException { return new Reader(new File("C:\\Users\\ad\\Desktop\\ip\\GeoLite2-City.mmdb")); } @Bean public Reader asnReader() throws IOException { return new Reader(new File("C:\\Users\\ad\\Desktop\\ip\\GeoLite2-ASN.mmdb")); } @Bean public Reader cnReader() throws IOException { return new Reader(new File("C:\\Users\\ad\\Desktop\\ip\\GeoCN.mmdb")); } } ``` GeoIPService.java ``` import javax.servlet.http.HttpServletRequest; import java.util.Map; public interface GeoIPService { IPInfo getIpInfo(String ip); IPInfo getIpInfo(HttpServletRequest request); } ``` GeoIPServiceImpl.java ``` import com.maxmind.db.Reader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.InetAddress; import java.util.*; import java.util.stream.Collectors; @Service public class GeoIPServiceImpl implements GeoIPService { private final Reader cityReader; private final Reader asnReader; private final Reader cnReader; private final List lang = Arrays.asList("zh-CN", "en"); private final List provinces = Arrays.asList( "内蒙古", "黑龙江", "河北", "山西", "吉林", "辽宁", "江苏", "浙江", "安徽", "福建", "江西", "山东", "河南", "湖北", "湖南", "广东", "海南", "四川", "贵州", "云南", "陕西", "甘肃", "青海", "广西", "西藏", "宁夏", "新疆", "北京", "天津", "上海", "重庆" ); private static final Map ASN_MAP = new HashMap() {{ // 有线电视/网络服务商 put(9812, "东方有线"); put(9389, "中国长城"); put(17962, "天威视讯"); put(17429, "歌华有线"); put(7497, "科技网"); put(24139, "华数"); put(9801, "中关村"); put(4538, "教育网"); put(24151, "CNNIC"); // 中国移动 put(38019, "中国移动"); put(139080, "中国移动"); put(9808, "中国移动"); put(24400, "中国移动"); put(134810, "中国移动"); put(24547, "中国移动"); put(56040, "中国移动"); put(56041, "中国移动"); put(56042, "中国移动"); put(56044, "中国移动"); put(132525, "中国移动"); put(56046, "中国移动"); put(56047, "中国移动"); put(56048, "中国移动"); put(59257, "中国移动"); put(24444, "中国移动"); put(24445, "中国移动"); put(137872, "中国移动"); put(9231, "中国移动"); put(58453, "中国移动"); // 中国电信 put(4134, "中国电信"); put(4812, "中国电信"); put(23724, "中国电信"); put(136188, "中国电信"); put(137693, "中国电信"); put(17638, "中国电信"); put(140553, "中国电信"); put(4847, "中国电信"); put(140061, "中国电信"); put(136195, "中国电信"); put(17799, "中国电信"); put(139018, "中国电信"); put(133776, "中国电信"); put(58772, "中国电信"); put(146966, "中国电信"); put(63527, "中国电信"); put(58539, "中国电信"); put(58540, "中国电信"); put(141998, "中国电信"); put(138169, "中国电信"); put(139203, "中国电信"); put(58563, "中国电信"); put(137690, "中国电信"); put(63838, "中国电信"); put(137694, "中国电信"); put(137698, "中国电信"); put(136167, "中国电信"); put(148969, "中国电信"); put(134764, "中国电信"); put(134770, "中国电信"); put(148981, "中国电信"); put(134774, "中国电信"); put(136190, "中国电信"); put(140647, "中国电信"); put(132225, "中国电信"); put(140485, "中国电信"); put(4811, "中国电信"); put(131285, "中国电信"); put(137689, "中国电信"); put(137692, "中国电信"); put(140636, "中国电信"); put(140638, "中国电信"); put(140345, "中国电信"); put(38283, "中国电信"); put(140292, "中国电信"); put(140903, "中国电信"); put(17897, "中国电信"); put(134762, "中国电信"); put(139019, "中国电信"); put(141739, "中国电信"); put(141771, "中国电信"); put(134419, "中国电信"); put(140276, "中国电信"); put(58542, "中国电信"); put(140278, "中国电信"); put(139767, "中国电信"); put(137688, "中国电信"); put(137691, "中国电信"); put(4809, "中国电信"); put(58466, "中国电信"); put(137687, "中国电信"); put(134756, "中国电信"); put(134760, "中国电信"); put(133774, "中国电信"); put(133775, "中国电信"); put(4816, "中国电信"); put(134768, "中国电信"); put(58461, "中国电信"); put(58519, "中国电信"); put(58520, "中国电信"); put(131325, "中国电信"); // 中国联通 put(4837, "中国联通"); put(4808, "中国联通"); put(134542, "中国联通"); put(134543, "中国联通"); put(10099, "中国联通"); put(140979, "中国联通"); put(138421, "中国联通"); put(17621, "中国联通"); put(17622, "中国联通"); put(17816, "中国联通"); put(140726, "中国联通"); put(17623, "中国联通"); put(136958, "中国联通"); put(9929, "中国联通"); put(58519, "中国联通"); put(140716, "中国联通"); put(4847, "中国联通"); put(136959, "中国联通"); put(135061, "中国联通"); put(139007, "中国联通"); // 云服务商 put(59019, "金山云"); put(135377, "优刻云"); put(45062, "网易云"); put(137718, "火山引擎"); put(37963, "阿里云"); put(45102, "阿里云国际"); put(45090, "腾讯云"); put(132203, "腾讯云国际"); put(55967, "百度云"); put(38365, "百度云"); put(58519, "华为云"); put(55990, "华为云"); put(136907, "华为云"); // 其他运营商 put(4609, "澳門電訊"); put(134773, "珠江宽频"); put(1659, "台湾教育网"); put(8075, "微软云"); put(17421, "中华电信"); put(3462, "HiNet"); put(13335, "Cloudflare"); put(55960, "亚马逊云"); put(14618, "亚马逊云"); put(16509, "亚马逊云"); put(15169, "谷歌云"); put(396982, "谷歌云"); put(36492, "谷歌云"); }}; @Autowired public GeoIPServiceImpl(Reader cityReader, Reader asnReader, Reader cnReader) { this.cityReader = cityReader; this.asnReader = asnReader; this.cnReader = cnReader; } @Override public IPInfo getIpInfo(String ip) { IPInfo info = new IPInfo(); info.setIp(ip); try { InetAddress ipAddress = InetAddress.getByName(ip); // 处理ASN信息 processAsnInfo(ipAddress, info); // 处理City信息 Map cityInfo = cityReader.get(ipAddress,Map.class); if (cityInfo != null) { processCityInfo(cityInfo, info); // 如果是中国IP,处理GeoCN数据库 if (isChinaIp(info)) { processCnInfo(ipAddress, info); } } } catch (Exception e) { e.printStackTrace(); info.setError(e.getMessage()); } return info; } @Override public IPInfo getIpInfo(HttpServletRequest request) { String ip = Optional.ofNullable(request.getHeader("X-Forwarded-For")) .map(xff -> xff.split(",")[0]) .orElse(request.getRemoteAddr()); return getIpInfo(ip); } private void processAsnInfo(InetAddress ipAddress, IPInfo info) throws IOException { Map asnInfo = asnReader.get(ipAddress,Map.class); if (asnInfo == null) return; ASInfo as = new ASInfo(); as.setNumber(Integer.parseInt(asnInfo.get("autonomous_system_number").toString())); as.setName(asnInfo.get("autonomous_system_organization").toString()); String ispName = getAsInfo(as.getNumber()); if (ispName != null) { as.setInfo(ispName); } info.setAs(as); } private void processCityInfo(Map cityInfo, IPInfo info) { // 处理网络前缀 Integer prefix = (Integer) cityInfo.get("prefix_len"); if (prefix == null) prefix = 24; // 默认值 info.setAddr(getAddr(info.getIp(), prefix)); // 处理国家信息 if (cityInfo.get("country") != null) { Map country = (Map) cityInfo.get("country"); CountryInfo countryInfo = new CountryInfo(); countryInfo.setCode((String) country.get("iso_code")); countryInfo.setName(getCountryName(country)); info.setCountry(countryInfo); } // 处理注册国家信息 if (cityInfo.get("registered_country") != null) { Map regCountry = (Map) cityInfo.get("registered_country"); CountryInfo regCountryInfo = new CountryInfo(); regCountryInfo.setCode((String) regCountry.get("iso_code")); regCountryInfo.setName(getCountryName(regCountry)); info.setRegisteredCountry(regCountryInfo); } // 处理地区信息 List regions = new ArrayList<>(); if (cityInfo.get("subdivisions") != null) { List> subdivisions = (List>) cityInfo.get("subdivisions"); for (Map subd : subdivisions) { regions.add(getDescription(subd)); } } // 处理城市信息 if (cityInfo.get("city") != null) { Map city = (Map) cityInfo.get("city"); String cityName = getDescription(city); if (regions.isEmpty() || !regions.get(regions.size() - 1).contains(cityName)) { regions.add(cityName); } } info.setRegions(deDuplicate(regions)); } private void processCnInfo(InetAddress ipAddress, IPInfo info) throws IOException { Map cnData = cnReader.get(ipAddress,Map.class); GeoCNResponse cnInfo = new GeoCNResponse( (String) cnData.get("province"), (String) cnData.get("city"), (String) cnData.get("districts"), (String) cnData.get("isp"), (String) cnData.get("net"), (Integer) cnData.getOrDefault("prefix_len", 24) ); if (cnInfo == null) return; // 更新地址信息 info.setAddr(getAddr(info.getIp(), cnInfo.getPrefixLen())); // 处理地区信息 List regions = new ArrayList<>(); if (cnInfo.getProvince() != null) regions.add(cnInfo.getProvince()); if (cnInfo.getCity() != null) regions.add(cnInfo.getCity()); if (cnInfo.getDistricts() != null) regions.add(cnInfo.getDistricts()); info.setRegions(deDuplicate(regions)); // 处理简短地区信息 List regionsShort = new ArrayList<>(); if (cnInfo.getProvince() != null) regionsShort.add(provinceMatch(cnInfo.getProvince())); if (cnInfo.getCity() != null) regionsShort.add(cnInfo.getCity().replace("市", "")); if (cnInfo.getDistricts() != null) regionsShort.add(cnInfo.getDistricts()); info.setRegionsShort(deDuplicate(regionsShort)); // 更新ISP信息 if (info.getAs() == null) { info.setAs(new ASInfo()); } info.getAs().setInfo(cnInfo.getIsp()); // 设置网络类型 if (cnInfo.getNet() != null) { info.setType(cnInfo.getNet()); } } // 辅助方法 (与Python版本完全一致的功能) private String getAsInfo(Integer number) { return ASN_MAP.get(number); } private String getDescription(Map geoObj) { if (geoObj.get("names") == null) return ""; Map names = (Map) geoObj.get("names"); for (String l : lang) { if (names.containsKey(l)) { return names.get(l); } } return names.get("en"); } private String getCountryName(Map country) { String name = getDescription(country); if (Arrays.asList("香港", "澳门", "台湾").contains(name)) { return "中国" + name; } return name; } private String provinceMatch(String s) { for (String province : provinces) { if (s.contains(province)) { return province; } } return ""; } private List deDuplicate(List regions) { return regions.stream() .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); } private String getAddr(String ip, int prefix) { try { // 简化实现,实际应使用类似Python的ipaddress计算 return ip + "/" + prefix; } catch (Exception e) { return ip + "/" + prefix; } } private boolean isChinaIp(IPInfo info) { return info.getCountry() != null && "CN".equals(info.getCountry().getCode()) && (info.getRegisteredCountry() == null || "CN".equals(info.getRegisteredCountry().getCode())); } } ``` 接口中调用即可。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4791c87f973d4e1ba96edf609c4c905a.png) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/9f0596b82f4b4bb79585d8bf56d169d2.png) ## 项目仓库地址 [https://gitee.com/Super_TongYao/offline-ip-library.git](https://gitee.com/Super_TongYao/offline-ip-library.git) Java运行后访问:http://localhost:9000/api/ip/8.8.8.8 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f8bfbbb367e948369983e943cc080929.png)