API网关【gateway 】

Stella981
• 阅读 589

最近在公司进行API网关重写,公司内采用serverMesh进行服务注册,调用,这里结合之前学习对API网关服务进行简单的总结与分析。 由于采用了大量的nginx相关的东西,所以在此记录一下:

在nginx使用openresty

加入nginx模块

编辑nginx下conf配置文件nginx.conf

# vi nginx.conf
在server模块加上
location /helloworld {
default_type text/html;
content_by_lua 'ngx.say("hello world")';
}

 检查配置文件是否正确

# /usr/local/openresty/nginx/sbin/nginx -t -c /usr/local/openresty/nginx/conf/nginx.conf

重启nginx

# ./nginx -s reload

访问http://ip/helloworld ,输出helloworld

nginx的内部变量

名称 说明
$arg_name 请求中的name参数
$args 请求中的参数
$binary_remote_addr 远程地址的二进制表示
$body_bytes_sent 已发送的消息体字节数
$content_length HTTP请求信息里的"Content-Length"
$content_type 请求信息里的"Content-Type"
$document_root 针对当前请求的根路径设置值
$document_uri 与$uri相同; 比如 /test2/test.php
$host 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名
$hostname 机器名使用 gethostname系统调用的值
$http_cookie cookie 信息
$http_referer 引用地址
$http_user_agent 客户端代理信息
$http_via 最后一个访问服务器的Ip地址。
$http_x_forwarded_for 相当于网络访问路径
$is_args 如果请求行带有参数,返回“?”,否则返回空字符串
$limit_rate 对连接速率的限制
$nginx_version 当前运行的nginx版本号
$pid worker进程的PID
$query_string 与$args相同
$realpath_root 按root指令或alias指令算出的当前请求的绝对路径。其中的符号链接都会解析成真是文件路径
$remote_addr 客户端IP地址
$remote_port 客户端端口号
$remote_user 客户端用户名,认证用
$request 用户请求
$request_body 这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义
$request_body_file 客户端请求主体信息的临时文件名
$request_completion 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空
$request_filename 当前请求的文件路径名,比如/opt/nginx/www/test.php
$request_method 请求的方法,比如"GET"、"POST"等
$request_uri 请求的URI,带参数; 比如http://localhost:88/test1/
$scheme 所用的协议,比如http或者是https
$server_addr 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费)
$server_name 请求到达的服务器名
$server_port 请求到达的服务器端口号
$server_protocol 请求的协议版本,"HTTP/1.0"或"HTTP/1.1"
$uri 请求的URI,可能和最初的值有不同,比如经过重定向之类的

测试获取变量

location /test_url {
    echo "url:$uri";
}

location /test_url {
            echo "url:$uri";
            echo "full url : $host$request_uri";
}

openresty 使用redis

连接redis服务器

---定义 redis关闭连接的方法
local function close_redis(red)  
    if not red then  
        return  
    end  
    local ok, err = red:close()  
    if not ok then  
        ngx.say("close redis error : ", err)  
    end  
end  

建立连接

local ip = "192.168.31.247"  
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then  
    ngx.say("connect to redis error : ", err)  
    return close_redis(red)  
end  

调用API设置key

ok, err = red:set("msg", "hello world")  
if not ok then  
    ngx.say("set msg error : ", err)  
    return close_redis(red)  
end  

调用API获取key值

local resp, err = red:get("msg")  
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_redis(red)  
end 

redis连接池

local function close_redis(red)  
    if not red then  
        return  
    end  
    --释放连接(连接池实现)  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --连接池大小  
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end  

访问频率控制:

我们用redis的key表示用户,value表示用户的请求频次,再利用过期时间实现单位时间

要求10秒内只能访问10次frequency请求,超过返回403

首先为nginx.conf配置文件,nginx.conf部分内容如下:

location /frequency {
    access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua;
    echo "访问成功";
}

编辑access_by_limit_frequency.lua

local function close_redis(red)  
    if not red then  
        return
    end  
    --释放连接(连接池实现)  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --连接池大小  
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end

local function errlog(...)
    ngx.log(ngx.ERR, "redis: ", ...)
end

local redis = require "resty.redis"  --引入redis模块
local red = redis:new()  --创建一个对象,注意是用冒号调用的

--设置超时(毫秒)  
red:set_timeout(1000) 
--建立连接  
local ip = "192.168.31.247"  
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then  
    close_redis(red)
    errlog("Cannot connect");
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)   
end  

local key = "limit:frequency:login:"..ngx.var.remote_addr

--得到此客户端IP的频次
local resp, err = red:get(key)
if not resp then  
    close_redis(red)
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 获取值失败
end 

if resp == ngx.null then   
    red:set(key, 1) -- 单位时间 第一次访问
    red:expire(key, 10) --10秒时间 过期
end  

if type(resp) == "string" then 
    if tonumber(resp) > 10 then -- 超过10次
        close_redis(red)
        return ngx.exit(ngx.HTTP_FORBIDDEN) --直接返回403
    end
end

--调用API设置key  
ok, err = red:incr(key)  
if not ok then  
    close_redis(red)
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 报错 
end  

close_redis(red)  

请求地址:/frequency

10秒内 超出10次 ,返回403

10秒后,又可以访问了

如果我们想整个网站 都加上这个限制条件,那只要把

access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua;

这个配置,放在server部分,让所有的location 适用就行了

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这