道者编程


redis实用小实例

1:发送手机短信,1分钟限制3次

分析:给用户发送短信,首先验证手机号码格式,然后判断在1分钟以内是否发送过3次,有很多种做法,比如基于mysql实现,每发送一次,记录一条数据:手机号,时间戳。很麻烦,如果用redis处理非常简单:

思路:基于redis的TTL,设置生命周期,key 设置一分钟,每次访问加1,然后判断数量,1分钟后redis会自动回收注销key。

(1)伪代码:golang,稍微封装下:

package main
import(
	"fmt"
	"os"
	"github.com/gomodule/redigo/redis"
)
func main(){
	conn := connect()
	defer conn.Close()//记得销毁本次链连接
	phoneNum := "13512345678" //手机号
	key := "shortMsg:limit:" + phoneNum

	// NX:表示key不存在则设置,设置值为0 过期时间:60s 
	_ ,setErr := conn.Do("SET",key,0,"EX",60,"NX")
	checkError(setErr) //错误提示
	count , _ := conn.Do("INCR",key) //加 1 返回KEY的值
	//conn.DO返回的是interface,需要转换
	if( count.(int64) <= 3){
		fmt.Println("OK")
	}else{
		fmt.Println("超过次数")
	}
}
//连接
func connect()redis.Conn{
	const ip string = "192.168.17.160" //redis地址
	const port string = "6379" //端口 
	conn := ip+":"+port
	passrord := "123" //密码
	// 连接redis
	c,err := redis.Dial("tcp",conn,redis.DialPassword(passrord))
	checkError(err)
	return c 
}
//错误提示
func checkError(err error){
	if err != nil {
		fmt.Println("Error is ",err)
		os.Exit(-1)
	}
}

(2)伪代码:php,假装封装下连接

<?php
date_default_timezone_set("PRC");

$phoneNum = "13512345678"; //手机号
$key = "shortMsg:limit:".$phoneNum;
$conn = connect(); //连接
$isExists = $conn->set($key,1,array("EX"=>60,"NX"));
if($isExists != "" || $conn->incr($key) <=3){
    echo "ok";
}else{
    echo "超过次数";
}

//连接
function connect(){
	$redis = new Redis();
	$redis->connect('192.168.17.160',6379); //连接服务器 返回【true | false】
	$redis->auth('123');  //登录验证密码,返回【true | false】
	return $redis;
}

这种可以扩展出其他一些使用场景,比如限制一些爬虫,或者是恶意频繁访问,如:1秒钟限制5次……,API每天限制多少次、同一个IP每天投票多少次等等!

2:发送短信,一天之内发送10次,且1分钟限制一次

分析:这里要用两个key,一个是记录1天的次数,一个是记录1分钟的次数

思路:基本思路同上,不过用到了另外一个命令,设置当天过期用到了redis的Expireat命令:用于以 UNIX 时间戳(unix timestamp)格式设置 key 的过期时间。key 过期后将不再可用。也就是我们设置某个时间点过期,只要设置这个时间点的时间戳就行了。

分两步:首先判断一天是否超过10次,如果没有超过再判断一分钟限制,一分钟限制很简单,我们保存1个key设置一分钟过期,如果存在key,说明1分钟内已经发送过,不能再发送。

(1)伪代码:golang

package main

import(
	"fmt"
	"os"
	"time"
	"github.com/gomodule/redigo/redis"
)

func main(){
	conn := connect()
	defer conn.Close()//记得销毁本次链连接
	phoneNum := "13512345678" //手机号

	if !dayData(phoneNum,conn) {
		fmt.Println("超过一天次数")
		return 
	}
	
	isExists := minData(phoneNum,conn)
	if isExists {
		fmt.Println("OK")
	} else{
		fmt.Println("超过每分钟次数")
	}
	
}

//一天10次
func dayData(phone string , c redis.Conn) bool {
	key := "shortMsg:day:" + phone 
	exists, _ := redis.Bool(c.Do("EXISTS", key))
	if !exists {
		_ , setErr := c.Do("SET",key,0)
		checkError(setErr) //错误提示
		_ , err := c.Do("Expireat",key,endTime()) //UNIX 时间戳(unix timestamp)格式设置 key 的过期时间
		checkError(err) //错误提示
	} 
	count , _ := c.Do("INCR",key) //加 1 返回KEY的值
	if( count.(int64) <= 10){
		return true
	}else{
		return false
	}
}

//一分钟1次
func minData(phone string , c redis.Conn) bool {
	key := "shortMsg:min:" + phone 
	exists, _ := redis.Bool(c.Do("EXISTS", key)) //如果不存在返回 设置key 返回ture
	if !exists {
		_ ,setErr := c.Do("SET",key,1,"EX",60,"NX")
		checkError(setErr) //错误提示
		return true
	}else{
		return false
	}
}

//获取当天 23:59:59秒的时间戳
func endTime() int64 {
	t := time.Now()
	return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, t.Location()).Unix()
}

//连接
func connect()redis.Conn{
	const ip string = "192.168.17.160" //redis地址
	const port string = "6379" //端口 
	conn := ip+":"+port
	passrord := "123" //密码
	// 连接redis
	c,err := redis.Dial("tcp",conn,redis.DialPassword(passrord))
	checkError(err)
	return c 
}

//错误提示
func checkError(err error){
	if err != nil {
		fmt.Println("Error is ",err)
		os.Exit(-1)
	}
}

(2)伪代码:php

<?php
date_default_timezone_set("PRC");

$phoneNum = "13512345678"; //手机号
$conn = connect(); //连接
if(dayData($phoneNum,$conn) === false ){
	echo "超过一天次数";
}else{
	if(minData($phoneNum,$conn) === false ){
		echo "超过每分钟次数";
	}else {
		echo "ok";
	}
}

//一天10次
function dayData($phone,$redis){
	$key = "shortMsg:day:".$phone;
	if(!$redis->exists($key)){ //如果不存在
		$redis->set($key,0); // 设置0次
		$redis->expireat($key,endTime()); //设置当天23:59:59过期
	}
	$count = $redis->incr($key); //加1
	if($count > 10){
		return false;
	}else {
		return true;
	}
}
//一分钟1次
function minData($phone,$redis){
	$key = "shortMsg:min:".$phone;
	if(!$redis->exists($key)){ //如果不存在
		$redis->set($key,1,array("EX"=>60)); //设置值 60秒过期
		return true;
	}else{
		return false;
	}
}
//连接
function connect(){
	$redis = new Redis();
	$redis->connect('192.168.17.160',6379); //连接服务器 返回【true | false】
	$redis->auth('123');  //登录验证密码,返回【true | false】
	return $redis;
}

//获取当天 23:59:59秒的时间戳
function endTime(){
	return mktime(23, 59, 59, date("m"), date("d"), date("Y"));
}
 


最新评论:
我要评论:

看不清楚


链接