最近无意中查看nginx发现好多疑似爬虫ip,遂临时起意能不能搞个频率限制。

以下用我使用的刘志超先生开发的Leaveit主题为例

一. 配置文件更改baseURL

// hugo config.toml
baseURL = "/public"avatar = "/public/images/me/avatar.jpeg" Wechat = "/public/images/me/wechat.png"

二. 更改部分模板html中的href

// 更改themes-leaveit-layouts-partials-home_profile.html
<div class="avatar"><a href="/public/posts/"> <img src="{{ (printf "%s%s" $cdn_url $avatar)}}"> </a>
</div>

以上修改保证可以设置一个public静态文件夹可以访问所有内容(如果有上传图片保存在服务器本地的0.0,请记得修改markdown中的图片url)*

三. 编写网关代码

/*
目录结构:blog_ratelimit- apigw- common- code.go- conf- config.go- config.json- middleware- ratelimit.go- redisdb- redisdb.go- public- main.go*/

code.go

package commonconst (_ int32 = iota +999StatusBlackList    // 1000 黑名单限制
)

config.go

package confimport ("encoding/json""log""os"
)type Configuration struct {RedisAddr string `json:"redis_addr"` // redis地址RedisPass string `json:"redis_pass"` // redis密码
}var DefaultConfig *Configurationfunc InitConfig(configLoc string){_, err := os.Stat(configLoc)if err != nil {log.Panic("配置文件路径不存在")}file,_ := os.Open(configLoc)defer file.Close()decoder := json.NewDecoder(file)DefaultConfig = &Configuration{}err = decoder.Decode(DefaultConfig)if err != nil {log.Panic(err)}
}

config.json

{"redis_addr": "192.168.50.15:6379","redis_pass": ""
}

ratelimit.go


package middlewareimport ("blog_ratelimit/apigw/common""blog_ratelimit/apigw/redisdb""errors""fmt""github.com/gin-gonic/gin""github.com/go-redis/redis""net/http""strconv""time"
)const (blackListKey = "blacklist"
)func IpVerify() gin.HandlerFunc {return func(ctx *gin.Context) {visitorIP := ctx.Request.Header.Get("X-real-ip")// fmt.Println(visitorIP)rdb := redisdb.GetRatePool()// 判断是否在黑名单timeOrigin := rdb.HGet(blackListKey, visitorIP).Val()err := blackListVerify(timeOrigin,visitorIP, rdb)if err != nil {ctx.JSON(http.StatusOK, gin.H{"code": common.StatusBlackList,"msg":  err.Error(),})ctx.Abort()return}// 如果不存在于黑名单lenList, _ := rdb.LLen(visitorIP).Result()// 如果第一次登陆或频率限制外if lenList == 0 {// 如果为空跳过,设置后跳过// 添加IP listrdb.LPush(visitorIP, visitorIP)// 设置过期时间rdb.Expire(visitorIP, 1000*1000*1000)ctx.Next()}else if lenList >0 && lenList <3 {rdb.LPush(visitorIP, visitorIP)ctx.Next()}else {// 加入黑名单rdb.HSet(blackListKey,visitorIP,time.Now().Local().Unix())ctx.Abort()return}}
}func blackListVerify(ot,visitorIP string,rdb *redis.Client) error {// 如果有值,进一步判断if ot != "" {// 如果value的时间和当前时间差超过十分钟,解除限制timeOriginInt, _ := strconv.Atoi(ot)oTimeUnix := time.Unix(int64(timeOriginInt),0).Local()subTime := time.Now().Sub(oTimeUnix)if subTime > 10*time.Minute {// 超过限制时间 解除限制rdb.HDel(blackListKey,visitorIP)return nil}else {//return errors.New(fmt.Sprintf("您已被加入黑名单,剩余限制时间:%v",10*time.Minute-subTime))}}// 不存在返回nilreturn nil
}

redisdb.go

package redisdbimport ("blog_ratelimit/apigw/conf""github.com/go-redis/redis""log""time"
)var ratePool *redis.Clientfunc init(){conf.InitConfig("./apigw/conf/config.json")rateRedisInit()
}func rateRedisInit(){client := redis.NewClient(&redis.Options{Addr:         conf.DefaultConfig.RedisAddr,Password:     conf.DefaultConfig.RedisPass,DB:           1,PoolSize:     50,MinIdleConns: 20,IdleTimeout:  30*time.Second,})_, err := client.Ping().Result()if err != nil {log.Panic("failed to connect redis.")}ratePool = client
}func GetRatePool() * redis.Client {return ratePool
}

main.go

package mainimport ("blog_ratelimit/apigw/middleware""github.com/gin-gonic/gin""net/http"
)func main() {router := gin.Default()router.Static("/public/","./public")router.Use(middleware.IpVerify())router.GET("/", func(context *gin.Context) {context.Redirect(http.StatusFound,"/public/index.html")})router.Run(":8080")
}

四. 修改markdown图片链接脚本

package mainimport ("errors""fmt""io""io/ioutil""log""os""path/filepath""regexp""strings""time"
)const (DirLoc  = "/Users/huangxuchen/dvpos/content/posts"OldWord = "/images/blog/"NewWord = "/public/images/blog/"
)func replaceLogs(errorInfo string) {file, _ := os.OpenFile("./utils/replacewords/logs.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)log.New(io.MultiWriter(file, os.Stderr), "[Failed]", log.Ldate|log.Ltime|log.Llongfile).Println(errorInfo)
}func getFileList() ([]string, error) {var fileList []string// 获取所有文件路径err := filepath.Walk(DirLoc, func(path string, info os.FileInfo, err error) error {if info == nil {return err}// 匹配以md结尾文件加入sliceisMatch, _ := regexp.MatchString("^*.md$", info.Name())if isMatch{fileList = append(fileList, path)}return nil})return fileList, err
}func replaceWord(fileList []string) error {for _, v := range fileList {//删除原文件替换后逐行写入新文件//file, err := os.OpenFile(v,os.O_RDWR,0766)//if err != nil {// return errors.New(fmt.Sprintf("failed to open file:%v,Error:%v", v, err.Error()))//}//reader := bufio.NewReader(file)//defer file.Close() 删除源文件//os.Remove(v)//newFile, err := os.OpenFile(v,os.O_RDWR|os.O_CREATE,0766)//if err != nil {// return errors.New(fmt.Sprintf("failed to create new file:%v,Error:%v", v, err.Error()))//}//defer newFile.Close()//for {// line, _, err := reader.ReadLine()//    if err != nil {//      if err == io.EOF {//          break//     } else {//          return errors.New(fmt.Sprintf("failed to read file:%v,Error:%v", v, err.Error()))//        }// }// // 判断是否包含需要替换的内容//  if strings.Contains(string(line), OldWord){//       newLine := strings.Replace(string(line), OldWord, NewWord,-1)//        _, err = newFile.WriteString(newLine+"\n")//        if err != nil {//          return errors.New(fmt.Sprintf("failed to replace word at file:%v,Error:%v", v, err.Error()))//     }// }else {//       _, err := newFile.WriteString(string(line)+"\n")//      if err != nil {//          return errors.New(fmt.Sprintf("failed to replace word at file:%v,Error:%v", v, err.Error()))//     }// }//}// 简单粗暴(耗时短)file, err := ioutil.ReadFile(v)if err != nil {return errors.New(fmt.Sprintf("failed to read file:%v,Error:%v", v, err.Error()))}newFile := strings.Replace(string(file), OldWord, NewWord, -1)err = ioutil.WriteFile(v, []byte(newFile), 0)if err != nil {return errors.New(fmt.Sprintf("failed to replace word at file:%v,Error:%v", v, err.Error()))}}return nil
}func main() {fmt.Println("Start to replace word...")fileList, err := getFileList()if err != nil {fmt.Println(err)return}//fmt.Println(fileList)now := time.Now()err = replaceWord(fileList)if err != nil {replaceLogs(err.Error())os.Exit(1)}costTime := time.Now().Sub(now)fmt.Printf("Finished! CostTime:%v",costTime)
}

五. nginx配置

worker_processes  1;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;server {listen       80;server_name  域名1;server_name  域名2;charset utf-8;rewrite ^(.*)$ https://$host$1  permanent;}server {listen       443 ssl;server_name  域名1;server_name 域名2;root   root地址;ssl_certificate      com.pem;ssl_certificate_key  com.key;ssl_session_cache    shared:SSL:1m;ssl_session_timeout  5m;ssl_ciphers  HIGH:!aNULL:!MD5;ssl_prefer_server_ciphers  on;location / {# 保存原始IPproxy_set_header X-real-ip           $remote_addr;proxy_pass http://127.0.0.1:8080/;}}}

待解决

  • 编写脚本修改markdown文章的图片url(已解决)
  • gin获取静态文件是否可以将单次同一文章下的多个资源请求视为一个请求(已解决过滤图片cssjs等资源请求)
  • nginx配置修改,原来是基于hugo静态文件的配置(已解决)
  • 视情况修改增加限制,比如增加频率策略,设置令牌,浏览器校验等
  • 暂时想到这么多

持续更新、有经验的大神希望能分享下经验~

尝试通过gin+redis为hugo博客添加频率限制反爬相关推荐

  1. 博客搭建十:hugo博客添加友链

    交个朋友,为博客添加友链功能(还不完善,显示界面不美观),详情参看https://ziyue.tech/friend/有好的解决办法会继续在这里更新. hugo博客文件架构: 注:以下操作均在你的本地 ...

  2. 创建hugo博客_如何创建您的第一个Hugo博客:实用指南

    创建hugo博客 Hugo is a great tool to use if you want to start a blog. 如果您想创建博客,Hugo是一个很好的工具. I use Hugo ...

  3. 创建hugo博客_Hugo + Firebase:如何在几分钟内免费创建自己的静态网站

    创建hugo博客 by Aravind Putrevu 通过Aravind Putrevu Hugo + Firebase:如何在几分钟内免费创建自己的静态网站 (Hugo + Firebase: H ...

  4. 在Linux系统搭建Hugo博客

    简介 Hugo是由Go语言实现的静态网站生成器.简单.易用.高效.易扩展.快速部署. 该篇文章是在Linux/Ubuntu系统下安装搭建 Hugo 博客. 本博客参考了该视频:https://www. ...

  5. Hugo项目实战-集成评论博客添加评论功能

    实践效果 Quick Start Install Hugo brew install hugo # or port install hugohugo version Create a New Site ...

  6. Hugo博客SEO优化

    文章目录 1.页面关键词 2.页面描述 3.Google搜索优化 4.百度搜索优化 5.必应搜索优化 6.参考资料 原文博客链接地址: Hugo博客SEO优化 1.页面关键词 为每篇博客文章设置标题. ...

  7. hugo博客html创建目录,使用Hugo来生成静态博客

    关于Hugo Hugo是一个用Go语言编写的静态网站生成器,它使用起来非常简单,相对于Jekyll复杂的安装设置来说,Hugo仅需要一个二进制文件hugo(hugo.exe)即可轻松用于本地调试和生成 ...

  8. Hugo博客部署到腾讯云轻量级服务器

    文章目录 一.前置条件 二.服务器下载nginx 三.防火墙设置 四.将静态网页传送到服务器 五.申请ssl证书 六.配置nginx的nginx.conf文件 七.后续发布文章 文章内容可能不全面和详 ...

  9. hugo本地服务器不显示文章,Windows10本地搭建hugo博客教程 – 有点嫌弃我自己的家庭版系统...

    大鸟前面的文章说了如何下载安装Git,安装了肯定是有用的,我们暂时先放在那边,现在大鸟准备在本地的Windows10里面搭建hugo博客. Hugo是由Go语言实现的静态网站生成器.简单.易用.高效. ...

最新文章

  1. Windows 7 状态栏图标消失恢复
  2. C# 使用正则表达式去掉字符串中的数字,或者去掉字符串中的非数字
  3. 所请求vi未加载至服务器内存_linux下tomcat端口请求数太大,导致服务器资源加载过慢的配置优化...
  4. 左神算法:判断二叉树是否为平衡二叉树(树形dp套路,Java版)
  5. 配置hibernate根据实体类自动建表功能
  6. sql同时向两个表插入数据_SQL入门-数据库和客户端的安装,表的创建和数据插入...
  7. Linux 命令之 who -- 打印当前登录用户/显示目前登入系统的用户信息。
  8. Spring Boot 页面国际化
  9. 解决Xshell无法连接虚拟机CentOS7问题
  10. linux resin mysql_【转】Linux下Resin+JSP+MySQL的安装和配置
  11. SQL SERVER中的二种获得自增长ID的方法
  12. 极兔68亿收购百世快递
  13. java中的implements如何打开_Java 中extends与implements使用方法
  14. 新手如何学习Java——Java学习路线图
  15. idea导入java项目步骤_idea导入javaweb项目
  16. Python接口自动化测试
  17. 服务器更换固态后如何安装系统,更换固态硬盘后安装操作系统的两种常用方法...
  18. 内存卡格式化不了怎么解决?内存卡格式化不了解决方法
  19. Unity实现AR扫描图片
  20. 认识ZBrush? 4R7视图区

热门文章

  1. 高通AR9342 5.8GHz大功率无线户外CPE
  2. MATLAB截面数据空间计量模型代码②
  3. android使用sax解析xml
  4. xamarin.forms_重构:从Xamarin Native到Xamarin.Forms
  5. linux 查看samtools版本,samtools 1.9
  6. Tessy — 嵌入式软件单元测试/ 集成测试工具
  7. 瑞萨e2studio(4)----使用J-Link烧写程序到瑞萨芯片
  8. mixin机制 vue_Vue Mixin用法
  9. 载誉而归,重磅发布!润和软件亮相2022开放原子全球开源峰会
  10. 大数据与人工智能都分不清楚,还想走向人生巅峰?