【网关开发】7.Openresty使用cosocket API 发送http与tcp网络请求

背景

为网关提供健康检查功能时需要对节点发送http或者tcp探活请求。Openresty 提供cosocket来处理非阻塞IO。

实现

跟工程结合在一起,这里简单拼接数据结构

local function __default_check_alive(status)
    return status >= 200 and status <= 299
end
local function debug_ctx()
    local ctx =  {
        peer = {ip = '10.218.22.239', port = '8090'},                                                 --目标机器
        ahc = {
            type = 'http',
            timeout = 3,
            check_http_send = "GET /ping HTTP/1.1\r\nHost: service_test.com\r\n\r\n",  -- 发送的数据内容
        },
        status_check = __default_check_alive
    }
    return ctx
end

发送http请求

local stream_sock = ngx.socket.tcp    -- 引入模块
local re_find = ngx.re.find

local function __check_http_peer(ahc, peer, status_check)
    local ok
    local req = ahc.check_http_send

    local sock, err = stream_sock()            -- 创建 TCP 的 cosocket 对象
    if not sock then
        ngx.log(ngx.ERR, "failed to create stream socket: " .. err)
        return false, err
    end

    sock:settimeout(ahc.timeout * 1000)      --设置超时时间

    ok, err = sock:connect(peer.ip, peer.port)  --建立连接
    if not ok then
        return false
    end

    local bytes, err = sock:send(req)    --发送数据
    if not bytes then
        return false
    end

    local status_line, err = sock:receive()  -- 接收数据
    if not status_line then
        if err == "timeout" then
            sock:close()  -- timeout errors do not close the socket.
        end
        return false
    end

    if status_check then
        local from, to, err = re_find(status_line,
                                      [[^HTTP/\d+\.\d+\s+(\d+)]],      --利用正则获取status code
                                      "joi", nil, 1)
        if err then
            ngx.log(ngx.ERR, "failed to parse status line: "..err)
        end

        if not from then
            sock:close()
            return false
        end

        local status = tonumber(status_line:sub(from, to))
        if not status_check(status) then
            -- ngx.log(ngx.ERR, status_line)
            sock:close()
            return false
        end
    end

    sock:close()
    return true
end

发送tcp请求


-- functional, check peer by tcp, returns bool indicate up or down
local function __check_tcp_peer(ahc, peer)
    local ok
    local sock, err = stream_sock()
    if not sock then
        ngx.log(ngx.ERR, "failed to create stream socket: " .. err)
        return false, err
    end

    sock:settimeout(ahc.timeout * 1000)

    ok, err = sock:connect(peer.ip, peer.port)
    if not ok then
        return false
    end
    sock:close()
    return true
end

遇到的问题

API disabled in the context of init_worker_by_lua*

这是因为我使用的地方是在init_worker_by_lua阶段,这阶段是不允许使用cosocket的,除了这些阶段还有
set_by_lua、log_by_lua、header_filter_by_lua、body_filter_by_lua、init_by_lua* 都是不允许使用的

-- 修改调用
ngx.timer.at(0, function (p, self)
        local ctx = down_peer_checker.debug_ctx()
        ngx.log(ngx.INFO,"down_peer_checker  check_peer "..tostring(down_peer_checker.check_peer(ctx)))
    end)

HTTP/1.1 400 Bad Request

主要是请求字符串格式问题、

GET /ping HTTP/1.1\r\n Host: service_test.com\r\n        错误
GET /ping HTTP/1.1\r\nHost: service_test.com\r\n\r\n   正确

总结与思考

cosocket知识与参考文章:https://zhuanlan.zhihu.com/p/507329735
存在部分封装,源码地址 https://github.com/zhaoshoucheng/openresty/blob/main/pkg/lua_script/upstream/down_peer_checker.lua

posted @ 2023-01-29 14:48  zscbest  阅读(355)  评论(0编辑  收藏  举报