zoukankan      html  css  js  c++  java
  • API网关【gateway 】- 3

    最近在公司进行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 适用就行了

  • 相关阅读:
    mysql性能优化学习笔记(1)优化目的、方向及数据库准备
    php笔试算法题:顺时针打印矩阵坐标蛇形算法
    离职了,一切从头开始
    mysql性能优化学习笔记(2)如何发现有问题的sql
    WTL的使用
    获取程序当前目录的绝对路径
    [读书笔记]《C#本质论》读书笔记
    [.NET]ConcurrentDictionary 线程安全的集合类
    RakNet中文手册
    Python SCons
  • 原文地址:https://www.cnblogs.com/zhenghongxin/p/10694846.html
Copyright © 2011-2022 走看看