IP 工具包 (iputil)
IsValidIP
验证 IP 地址格式是否正确
IsValidIP
验证 IP 地址字符串格式是否正确,支持 IPv4 和 IPv6 地址。
函数签名
func IsValidIP(ip string) bool参数
ip string- 要验证的 IP 地址字符串
返回值
bool-true表示有效的 IP 地址,false表示无效
支持的 IP 格式
IPv4 地址
- 标准格式:
192.168.1.1 - 零填充:
192.168.001.001(会被正确识别) - 回环地址:
127.0.0.1
IPv6 地址
- 完整格式:
2001:0db8:85a3:0000:0000:8a2e:0370:7334 - 压缩格式:
2001:db8:85a3::8a2e:370:7334 - 回环地址:
::1 - 映射地址:
::ffff:192.168.1.1
基本用法
package main
import (
"fmt"
"github.com/woodchen-ink/go-web-utils/iputil"
)
func main() {
testIPs := []string{
"192.168.1.1", // ✅ 有效的 IPv4
"2001:db8::1", // ✅ 有效的 IPv6
"::1", // ✅ IPv6 回环地址
"invalid-ip", // ❌ 无效格式
"192.168.1.256", // ❌ 超出范围
"", // ❌ 空字符串
"192.168.1", // ❌ 不完整的 IPv4
}
for _, ip := range testIPs {
if iputil.IsValidIP(ip) {
fmt.Printf("✅ %s 是有效的 IP 地址\n", ip)
} else {
fmt.Printf("❌ %s 不是有效的 IP 地址\n", ip)
}
}
}输出:
✅ 192.168.1.1 是有效的 IP 地址
✅ 2001:db8::1 是有效的 IP 地址
✅ ::1 是有效的 IP 地址
❌ invalid-ip 不是有效的 IP 地址
❌ 192.168.1.256 不是有效的 IP 地址
❌ 不是有效的 IP 地址
❌ 192.168.1 不是有效的 IP 地址实际应用场景
1. 输入验证
func validateIPInput(w http.ResponseWriter, r *http.Request) {
ipStr := r.FormValue("ip")
if !iputil.IsValidIP(ipStr) {
http.Error(w, "无效的 IP 地址格式", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "有效的 IP 地址: %s", ipStr)
}2. 配置文件验证
type ServerConfig struct {
AllowedIPs []string `json:"allowed_ips"`
BlockedIPs []string `json:"blocked_ips"`
}
func validateConfig(config *ServerConfig) error {
// 验证允许的 IP 列表
for _, ip := range config.AllowedIPs {
if !iputil.IsValidIP(ip) {
return fmt.Errorf("无效的允许 IP: %s", ip)
}
}
// 验证阻止的 IP 列表
for _, ip := range config.BlockedIPs {
if !iputil.IsValidIP(ip) {
return fmt.Errorf("无效的阻止 IP: %s", ip)
}
}
return nil
}3. IP 白名单/黑名单管理
type IPFilter struct {
whitelist map[string]bool
blacklist map[string]bool
}
func NewIPFilter() *IPFilter {
return &IPFilter{
whitelist: make(map[string]bool),
blacklist: make(map[string]bool),
}
}
func (f *IPFilter) AddToWhitelist(ip string) error {
if !iputil.IsValidIP(ip) {
return fmt.Errorf("无效的 IP 地址: %s", ip)
}
f.whitelist[ip] = true
return nil
}
func (f *IPFilter) AddToBlacklist(ip string) error {
if !iputil.IsValidIP(ip) {
return fmt.Errorf("无效的 IP 地址: %s", ip)
}
f.blacklist[ip] = true
return nil
}
func (f *IPFilter) IsAllowed(ip string) bool {
// 先检查黑名单
if f.blacklist[ip] {
return false
}
// 如果白名单为空,默认允许
if len(f.whitelist) == 0 {
return true
}
// 检查白名单
return f.whitelist[ip]
}4. 结合 GetClientIP 使用
func secureHandler(w http.ResponseWriter, r *http.Request) {
// 获取客户端 IP
clientIP := iputil.GetClientIP(r)
// 验证 IP 格式
if !iputil.IsValidIP(clientIP) {
log.Printf("获取到无效的客户端 IP: %s", clientIP)
http.Error(w, "无法识别客户端 IP", http.StatusBadRequest)
return
}
// 进一步处理
if iputil.IsPrivateIP(clientIP) {
fmt.Fprintf(w, "内网用户,IP: %s", clientIP)
} else {
fmt.Fprintf(w, "外网用户,IP: %s", clientIP)
}
}5. API 参数验证
type IPRangeRequest struct {
StartIP string `json:"start_ip"`
EndIP string `json:"end_ip"`
}
func validateIPRange(w http.ResponseWriter, r *http.Request) {
var req IPRangeRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "无效的 JSON", http.StatusBadRequest)
return
}
// 验证起始 IP
if !iputil.IsValidIP(req.StartIP) {
http.Error(w, "无效的起始 IP 地址", http.StatusBadRequest)
return
}
// 验证结束 IP
if !iputil.IsValidIP(req.EndIP) {
http.Error(w, "无效的结束 IP 地址", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "IP 范围有效: %s - %s", req.StartIP, req.EndIP)
}错误处理示例
func processIPList(ips []string) ([]string, error) {
var validIPs []string
var invalidIPs []string
for _, ip := range ips {
if iputil.IsValidIP(ip) {
validIPs = append(validIPs, ip)
} else {
invalidIPs = append(invalidIPs, ip)
}
}
if len(invalidIPs) > 0 {
return validIPs, fmt.Errorf("发现 %d 个无效的 IP 地址: %v",
len(invalidIPs), invalidIPs)
}
return validIPs, nil
}实现原理
IsValidIP 基于 Go 标准库的 net.ParseIP 函数实现:
func IsValidIP(ip string) bool {
return net.ParseIP(ip) != nil
}net.ParseIP 的特点:
- 零内存分配:验证失败时不分配内存
- 高性能:基于优化的解析算法
- 标准兼容:严格遵循 RFC 标准
性能说明
- 时间复杂度: O(n),其中 n 是 IP 字符串长度
- 内存开销: 验证失败时零分配,成功时分配解析后的 IP 对象
- 适用场景: 高频验证场景,如输入验证、配置检查等
相关函数
- GetClientIP - 获取客户端真实 IP 地址
- IsPrivateIP - 判断是否为私有网络 IP(在包文档中)