golang实现ip访问限制及提交次数

 更新时间:2024年10月21日 14:06:38   作者:Ai编码助手  
在 Web 应用中,通常会需要对 IP 访问进行限制以及控制提交次数,本文将使用中间件或者基于 Redis 这样的缓存服务来实现,感兴趣的可以了解下

在 Web 应用中,通常会需要对 IP 访问进行限制以及控制提交次数,以防止恶意攻击(例如暴力破解、DoS攻击、API滥用等)。为了实现这一功能,我们可以结合 Golang 的特性,使用中间件或者基于 Redis 这样的缓存服务来实现 IP 限制和提交次数的控制。

实现步骤

  • IP 访问限制:对每个 IP 的访问频次进行限制,比如每个 IP 每分钟只能访问某个接口 10 次。超过限制后,返回错误信息(例如 429 Too Many Requests)。
  • 提交次数限制:通过限制某个时间段内某个 IP 的提交次数,防止暴力破解或者滥用接口。
  • Redis(或其他存储系统)作为计数器:为了更好地实现这种限制,可以使用 Redis 等缓存系统来存储 IP 的访问记录、提交次数等,因为 Redis 的性能和易用性使它成为理想的选择。

核心概念

  • Rate Limiting(限流):根据 IP 限制某个时间段内的访问次数。
  • 请求次数计数:对每个 IP 进行计数,并基于计数来判断是否超过限制。
  • 时间窗口:设置一定的时间窗口(例如一分钟或五分钟),在这个时间段内统计 IP 的访问次数。

使用 Golang 及 Redis 实现 IP 访问限制和提交次数限制

这里我们使用 Redis 来存储和控制访问次数,并结合 Go 实现一个简单的 IP 访问限制中间件。

依赖库

你可以使用 Redis 官方的 Go 客户端 go-redis 来连接 Redis 进行操作。先安装这个库:

go get github.com/go-redis/redis/v8

实现代码

下面的代码演示了如何使用 Redis 来实现 IP 访问限制和提交次数限制。

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/go-redis/redis/v8"
)

// Redis client
var rdb *redis.Client

// 初始化 Redis 客户端
func initRedis() {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379", // Redis 地址
		Password: "",               // Redis 密码(如果有)
		DB:       0,                // 使用的 Redis 数据库
	})
}

// 获取客户端的 IP 地址
func getIP(r *http.Request) string {
	// 尝试从 X-Forwarded-For 或 X-Real-IP 获取真实 IP
	ip := r.Header.Get("X-Forwarded-For")
	if ip == "" {
		ip = r.Header.Get("X-Real-IP")
	}
	if ip == "" {
		ip = r.RemoteAddr
	}
	return ip
}

// 中间件:IP 访问限制
func rateLimitMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx := context.Background()
		ip := getIP(r)
		key := "rate_limit:" + ip

		// 获取 Redis 中的访问次数
		count, err := rdb.Get(ctx, key).Result()
		if err == redis.Nil {
			// 如果没有记录,设置计数为1,并设置过期时间
			err := rdb.Set(ctx, key, 1, time.Minute).Err() // 1 分钟限制
			if err != nil {
				http.Error(w, "Redis error", http.StatusInternalServerError)
				return
			}
		} else if err != nil {
			http.Error(w, "Redis error", http.StatusInternalServerError)
			return
		} else {
			// 将访问次数转换为整数
			countInt, _ := strconv.Atoi(count)
			if countInt >= 10 { // 假设限制为每分钟最多10次
				http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
				return
			}

			// 递增计数
			rdb.Incr(ctx, key)
		}

		next.ServeHTTP(w, r)
	}
}

// 示例处理器:提交处理
func submitHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Request successful")
}

func main() {
	// 初始化 Redis
	initRedis()

	// 创建 HTTP 服务器并添加中间件
	http.HandleFunc("/submit", rateLimitMiddleware(submitHandler))

	log.Println("Server is running on port 8080...")
	http.ListenAndServe(":8080", nil)
}

代码解析

Redis 客户端初始化

  • 使用 redis.NewClient() 初始化 Redis 客户端。
  • 通过 rdb.Set()rdb.Get() 来操作 Redis 中的计数器。

IP 获取

通过 getIP() 函数获取请求的客户端 IP 地址。该函数尝试从请求头中的 X-Forwarded-ForX-Real-IP 获取真实的 IP。如果没有,则使用 RemoteAddr

Rate Limiting 中间件

  • rateLimitMiddleware() 是核心的中间件函数,负责限制每个 IP 的访问次数。它使用 Redis 来存储每个 IP 的访问计数和限流时间窗口(这里设置为 1 分钟)。
  • 当 IP 的访问次数超过限制时,返回 HTTP 状态码 429 Too Many Requests

处理请求

  • submitHandler() 是一个简单的示例处理器,处理成功的请求。
  • 访问 /submit 时,经过中间件限制后,正常情况下返回 "Request successful"。

改进与扩展

  • 动态调整限流策略: 可以根据不同的用户类型、不同的 API 路径动态调整限流策略。例如,VIP 用户可能会有更高的访问频次。
  • IP 黑名单: 通过 Redis 或其他存储系统维护一个黑名单,遇到黑名单中的 IP 可以直接拒绝请求。
  • 按时间窗口的限流算法: 你可以采用滑动窗口、漏桶算法、令牌桶算法等更复杂的限流算法来实现更灵活的控制。
  • 使用 Redis Expire 特性: 在 Redis 中使用 SetEX(带过期时间的键设置)或 TTL 来确保计数器可以自动重置,避免手动管理。
  • 日志记录与报警: 可以结合日志系统,在某个 IP 频繁触发限制时记录日志或发送报警信息。

通过 Golang 和 Redis 的结合,可以轻松实现 IP 访问限制和提交次数控制。Redis 的高性能特性使其非常适合用作限流计数器的存储。在实际应用中,可以根据需要扩展该方案,例如使用不同的限流算法、结合 IP 黑名单等。

到此这篇关于golang实现ip访问限制及提交次数的文章就介绍到这了,更多相关go ip访问限制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go语言VScode see 'go help modules' (exit status 1)问题的解决过程

    go语言VScode see 'go help modules' (exit statu

    最近上手学习go语言,准备在VSCode上写程序的时候却发现出了一点问题,下面这篇文章主要给大家介绍了关于go语言VScode see 'go help modules'(exit status 1)问题的解决过程,需要的朋友可以参考下
    2022-07-07
  • 详解Golang中的通道机制与应用

    详解Golang中的通道机制与应用

    这篇文章主要来和大家一起深入探讨了Go语言中通道(Channel)的各个方面,文章详细解析了通道的类型、操作方法以及垃圾回收机制,有需要的可以了解下
    2023-10-10
  • Go语言标准库中math模块详细功能介绍与示例代码

    Go语言标准库中math模块详细功能介绍与示例代码

    Go语言的标准库math提供了一系列基础数学函数和常量,用于进行科学计算、几何计算和其他数学相关的操作,这篇文章主要介绍了Go语言标准库中math模块详细功能介绍与示例代码,需要的朋友可以参考下
    2025-03-03
  • Go语言实现简单留言板的方法

    Go语言实现简单留言板的方法

    这篇文章主要介绍了Go语言实现简单留言板的方法,涉及数据库、模板页面元素等留言板相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • Golang连接PostgreSQL基本操作的实现

    Golang连接PostgreSQL基本操作的实现

    PostgreSQL是常见的免费的大型关系型数据库,本文主要介绍了Golang连接PostgreSQL基本操作的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • Go语言中切片使用的注意事项小结

    Go语言中切片使用的注意事项小结

    切片是引用类型,相信对大家来说都不陌生,下面这篇文章主要给大家总结介绍了关于Go语言中切片使用的一些注意事项,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-01-01
  • go开发中引用静态库.a文件的方法

    go开发中引用静态库.a文件的方法

    这篇文章主要介绍了go开发中引用静态库.a文件的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Go如何优雅的使用字节池示例详解

    Go如何优雅的使用字节池示例详解

    在编程开发中,我们经常会需要频繁创建和销毁同类对象的情形,这样的操作很可能会对性能造成影响,这时常用的优化手段就是使用对象池(object pool),这篇文章主要给大家介绍了关于Go如何优雅的使用字节池的相关资料,需要的朋友可以参考下
    2022-08-08
  • Golang中 import cycle not allowed 问题的解决方法

    Golang中 import cycle not allowed 问题

    这篇文章主要介绍了Golang中 import cycle not allowed 问题的解决方法,问题从描述到解决都非常详细,需要的小伙伴可以参考一下
    2022-03-03
  • Go-Web框架中AOP方案的实现方式

    Go-Web框架中AOP方案的实现方式

    本文主要介绍了Go-Web框架中AOP方案的实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06

最新评论