狮子的魂/ip2region - 码云 - 开源中国 (gitee.com)
官方:ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,ip2region.db数据库只有数MB,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法
其实就是一个库,用于 IP地址解析定位用的,支持很多客户端,速度很快也不占内存,目前github已经到了10k star 了
特性:
速度快,内置三种查询算法,支持毫秒级查询,全部的查询客户端单次查询都在 0.x 毫秒级别,内置了三种查询算法
准确率高,数据聚合多个供应商的数据
体积小,空间优化形成了仅仅几兆的 ip2region.db 文件
支持多客户端,支持很多客户端,java、C#、php、c、python、nodejs、php扩展(php5和php7)、golang、rust、lua、lua_c, nginx
它的数据聚合了一些知名ip到地名查询提供商的数据,例如:(如果一下开放API或者数据都不给开放数据时ip2region将停止数据的更新服务)
淘宝IP地址库, http://ip.taobao.com/
GeoIP, https://geoip.com/
纯真IP库, http://www.cz88.net/
我们这里不导入官方的依赖,我们导入mica-ip2region
依赖,mica-ip2region
是 ip2region
的封装,方便 spring boot
用户使用。
mica: Spring Cloud 微服务开发核心工具集。 - Gitee.com
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>net.dreamlugroupId>
<artifactId>mica-ip2regionartifactId>
<version>2.6.8version>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.8.4version>
dependency>
dependencies>
这里有三个名词,分别是
- X-Forwarded-For:一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址。每个 IP 地址,每个值通过逗号+空格分开,最左边是最原始客户端的 IP 地址,中间如果有多层代理,每⼀层代理会将连接它的客户端 IP 追加在 X-Forwarded-For 右边。
- X-Real-IP:一般只记录真实发出请求的客户端IP
- Proxy-Client-IP:这个一般是经过 Apache http 服务器的请求才会有,用 Apache http 做代理时一般会加上 Proxy-Client-IP 请求头
- WL-Proxy-Client-IP:也是通过 Apache http 服务器,在 weblogic 插件加上的头。
在我们获取到用户的 IP 地址后,那么就可以获取对应的 ip 信息了
@Component
public class BrowserUtil {
private static final String UNKNOWN = "unknown";
/**
* 根据请求获取ip地址
*/
public String getIp(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();
}
String comma = ",";
String localhost = "127.0.0.1";
if (ip.contains(comma)) {
ip = ip.split(",")[0];
}
if (localhost.equals(ip)) {
// 获取本机真正的ip地址
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
}
}
return ip;
}
public JSONObject getBrowser(HttpServletRequest request) {
String browser = request.getHeader("User-Agent");//获取浏览器信息
UserAgent ua = UserAgentUtil.parse(browser);
String browserType = ua.getBrowser().toString();
String version = ua.getVersion();
String engine = ua.getEngine().toString();
String engineVersion = ua.getEngineVersion();
String os = ua.getOs().toString();
String platform = ua.getPlatform().toString();
Integer mobile = ua.isMobile() ? 1 : 0;
JSONObject json = new JSONObject();
json.set("browserType", browserType).set("platform", platform).set("mobile", mobile).set("os", os).set("platform", platform).set("version", version)
.set("engine",engine).set("engineVersion", engineVersion);
return json;
}
}
@RestController
@RequestMapping("/browser")
public class IpController {
@Autowired
BrowserUtil browserUtil;
@Autowired
private Ip2regionSearcher ip2regionSearcher; // 核心处理类,具体为什么可以直接 @Autowired,下面原理来说
@GetMapping("/getAddress")
public ResponseEntity<Object> address(HttpServletRequest request) throws IOException {
String ip = browserUtil.getIp(request);
IpInfo ipInfo = ip2regionSearcher.memorySearch(ip); // 根据ip地址获取到address
JSONObject entries = new JSONObject();
if (ipInfo != null) {
String country = ipInfo.getCountry();
String province = ipInfo.getProvince();
String city = ipInfo.getCity();
String isp = ipInfo.getIsp();
entries.set("country", country);
entries.set("province", province);
entries.set("city", city);
entries.set("isp", isp);
entries.set("ip", ip);
}
return new ResponseEntity<>(entries, HttpStatus.OK);
}
@GetMapping("/getAddressByIp")
public ResponseEntity<Object> addressByIp(@RequestParam("ip") String ip) throws IOException {
IpInfo ipInfo = ip2regionSearcher.binarySearch(ip); // 根据ip地址获取到address
assert ipInfo != null;
JSONObject entries = new JSONObject();
if (ipInfo != null) {
String country = ipInfo.getCountry();
String province = ipInfo.getProvince();
String city = ipInfo.getCity();
String isp = ipInfo.getIsp();
entries.set("country", country);
entries.set("province", province);
entries.set("city", city);
entries.set("isp", isp);
entries.set("ip", ip);
}
return new ResponseEntity<>(entries, HttpStatus.OK);
}
@GetMapping("/getBrowserInfo")
public JSONObject getBrowser(HttpServletRequest request) throws IOException {
return browserUtil.getBrowser(request);
}
//使用hutool工具调用纯真ip接口
@GetMapping("/cz88")
public JSONObject cs88(@RequestParam String ip) {
String fullUrl="https://www.cz88.net/api/cz88/ip/base?ip="+ip;
String result= HttpUtil.createGet(fullUrl).execute().body();
//hutool工具JSON字符串解析
return JSONUtil.parseObj(result);
}
}
FROM openjdk:latest
EXPOSE 9956
ADD target/ipBelongingPlace-0.0.1-SNAPSHOT.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["nohup","java","-jar","/app.jar","&"]
点击Run运行即可,这样就创建完成了镜像
docker run -d -p 9956:9956 --name bootIp springboot-ip:1.0
windowsDocker
服务器Docker
GET /browser/getAddress
{
"city":"内网IP",
"isp":"内网IP",
"ip":"172.17.0.1"
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
GET /browser/getBrowserInfo
如果使用apifox等测试工具是没有信息的
{
"browserType": "Unknown",
"platform": "Unknown",
"mobile": 0,
"os": "Unknown",
"engine": "Unknown"
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
GET /browser/getAddressByIp
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
ip | query | string | 否 | none |
{
"country":"中国",
"province":"上海",
"city":"上海",
"isp":"联通",
"ip":"220.248.12.158"
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
GET /browser/cz88
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
ip | query | string | 否 | none |
{
"code": 200,
"success": true,
"message": "操作成功",
"data": {
"ip": "103.216.43.5",
"countryCode": "CN",
"country": "中国",
"province": "北京",
"city": "北京",
"districts": "朝阳区",
"isp": "皓宽网络",
"geocode": "156011001005",
"netWorkType": "专线用户",
"mbRate": "暂未发现",
"score": "58%",
"honeypot": "暂未发现",
"netAddress": "登录查看",
"actionAddress": [
"中国-北京-北京-朝阳区"
],
"company": "暂未发现",
"locations": [
{
"latitude": "39.92**",
"longitude": "116.44**",
"radius": 34132
}
],
"openPorts": [],
"domains": [],
"breadRateMap": {
"RuijieNe": "0.191",
"其他": "0.500",
"Tp-LinkT": "0.309"
},
"deviceRateMap": {
"安卓": "0.677",
"iOS": "0.323"
}
},
"time": "2022-07-08 16:53:49"
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
博客详情 (warmwood.xyz)