<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 概述 Lua-resty-http 是一個基于 OpenResty 的 Lua 庫,是 OpenResty 項目中一個非常有用的模塊,用于從 Nginx 服務中發起 HTTP 請求。OpenResty 是一個基于 Nginx 與 LuaJIT 的全功能 Web 平臺,它集成了大量精心設計的 Nginx 模塊,以及大量的 Lua 庫。 lua-resty-http 庫允許你在 OpenResty 的 Lua 環境中輕松地發送 HTTP 請求,它提供了一個簡單易用的 API 來處理 HTTP 請求和響應。這使得在 Nginx 配置文件中編寫 Lua 腳本來處理 HTTP 請求和響應成為可能,從而可以構建高性能的 Web 應用和服務。如果你正在使用 OpenResty 并需要在 Nginx 配置中發起 HTTP 請求,lua-resty-http 是一個非常合適的選擇。 >項目地址:https://github.com/ledgetech/lua-resty-http ## 特性 * 異步非阻塞:該庫利用 nginx 的事件循環模型,讓 HTTP 請求在后臺執行,不會阻塞主線程,提高了整體性能。 * 連接池管理:它支持連接池的創建與管理,可以有效地復用 TCP 連接,減少握手延遲,提高服務響應速度。 * 豐富的 API 設計:Lua-Resty-HTTP 提供了一套完整的 API,包括設置超時、指定代理、添加請求頭、處理重定向、自定義認證等,使得開發過程更為便捷。 * SSL/TLS 支持:內置 SSL/TLS 功能,支持 HTTPS 請求,且允許自定義證書和密鑰。 * 錯誤處理:提供了詳細的錯誤信息,便于調試和故障排除。 ## 應用場景 * 數據獲取:從 RESTful API 獲取 JSON 或其他格式的數據。 * API 調用:在你的 OpenResty 應用中調用外部 Web 服務。 * 自動化測試:在 Lua 測試腳本中模擬 HTTP 請求,驗證服務行為。 * 日志報告:向遠程服務器發送日志或統計信息。 * 緩存刷新:根據 HTTP 響應自動更新本地緩存。 ## 使用 #### 安裝 這里通過OPM工具包安裝,更多請查看 [ddd](ddd) ``` opm get ledgetech/lua-resty-http ``` #### 基礎使用 使用 Lua-resty-http 發送 HTTP 請求的一個基本示例 ``` local httpc = require("resty.http").new() -- Single-shot requests use the `request_uri` interface. local res, err = httpc:request_uri("http://example.com/helloworld", { method = "POST", body = "a=1&b=2", headers = { ["Content-Type"] = "application/x-www-form-urlencoded", }, }) if not res then ngx.log(ngx.ERR, "request failed: ", err) return end -- At this point, the entire request / response is complete and the connection -- will be closed or back on the connection pool. -- The `res` table contains the expeected `status`, `headers` and `body` fields. local status = res.status local length = res.headers["Content-Length"] local body = res.body ``` ### 進階使用 `openresty.tinywan.com.conf`配置文件 ``` server { listen 80; server_name openresty.tinywan.com; location /lua_http_test { default_type "text/html"; lua_code_cache off; content_by_lua_file conf/lua/lua_http_test.lua; } } ``` `lua_http_test.lua` 腳本 ``` local httpc = require("resty.http").new() -- Single-shot requests use the `request_uri` interface. local res, err = httpc:request_uri("https://www.workerman.net/u/Tinywan", { method = "GET", body = "name=Tinywan&age=24", headers = { ["Content-Type"] = "application/x-www-form-urlencoded", }, ssl_verify = false, }) if not res then ngx.log(ngx.ERR, "request failed: ", err) return end local status = res.status local length = res.headers["Content-Length"] local body = res.body ngx.say(res.body) ``` 通過curl腳本測試請求打印結果 ```html $ curl -i http://openresty.tinywan.com/lua_http_test HTTP/1.1 200 OK Server: openresty/1.17.8.2 Date: Wed, 17 Jul 2024 09:42:10 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept-Encoding <!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="shortcut icon" href="/favicon.ico" /> <link href="https://cdn.workerman.net/css/bootstrap.min.css?v=20211126" rel="stylesheet"> <link href="https://cdn.workerman.net/css/main.css?v=20240705" rel="stylesheet"> <script src="https://cdn.workerman.net/js/jquery.min.js"></script> <script src="https://cdn.workerman.net/js/bootstrap.min.js?v=20211126"></script> <script src="https://cdn.workerman.net/js/functions.js?v=20220507"></script> <script type="text/javascript" charset="UTF-8" src="https://cdn.wwads.cn/js/makemoney.js" async></script> <title>Tinywan的主頁-分享-workerman社區</title> </head> ... </body> </html> ``` #### 項目應用 ``` --[[-------------------------------------------------------- * | Copyright (C) Shaobo Wan (Tinywan) * | Origin: 開源技術小棧 * |-------------------------------------------------------- --]] local helper = require "vendor.helper" local redis = require "resty.redis" local resty_lock = require "resty.lock" local http = require "resty.http" local log = ngx.log local ERR = ngx.ERR local live_ngx_cache = ngx.shared.live_ngx_cache -- 非error 日志開關 1:開啟,0:關閉 local log_switch = 1 local redis_host = "127.0.0.1" local redis_port = 6379 local redis_auth = "123456" local redis_timeout = 1000 -- set ngx.cache local function set_cache(key, value, exptime) if not exptime then exptime = 0 end local succ, err, forcible = live_ngx_cache:set(key, value, exptime) return succ end -- close 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 log(ERR, "set redis keepalive error : ", err) end end -- read redis local function read_redis(_host, _port, _auth, keys) local red = redis:new() red:set_timeout(redis_timeout) local ok, err = red:connect(_host, _port) if not ok then log(ERR, "connect to redis error : ", err) end -- 請注意這里 auth 的調用過程 local count count, err = red:get_reused_times() if 0 == count then ok, err = red:auth(_auth) if not ok then log(ERR, "failed to auth: ", err) return close_redis(red) end elseif err then log(ERR, "failed to get reused times: ", err) return close_redis(red) end local resp = nil if #keys == 1 then resp, err = red:get(keys[1]) else resp, err = red:mget(keys) end if not resp then log(ERR, keys[1] .. " get redis content error : ", err) return close_redis(red) end if resp == ngx.null then resp = nil end close_redis(red) if log_switch == 1 then log(ERR, "[2] [read_redis] content from redis.cache id = " .. keys[1]) -- tag data origin end return resp end -- write redis local function write_redis(_host, _port, _auth, keys, values) local red = redis:new() red:set_timeout(redis_timeout) local ok, err = red:connect(_host, _port) if not ok then log(ERR, "connect to redis error : ", err) end local count count, err = red:get_reused_times() if 0 == count then ok, err = red:auth(_auth) if not ok then log(ERR, "failed to auth: ", err) return close_redis(red) end elseif err then log(ERR, "failed to get reused times: ", err) return close_redis(red) end -- set data local resp = nil if #keys == 1 then resp, err = red:set(keys[1], values) else resp, err = red:mset(keys, values) end if not resp then log(ERR, "set redis live error : ", err) close_redis(red) end close_redis(red) return resp end -- get ngx.cache --[1]即使發生其他一些不相關的錯誤,您也需要盡快解除鎖定。 --[2]在釋放鎖之前,您需要從后端獲得的結果更新緩存,以便其他已經等待鎖定的線程在獲得鎖定后才能獲得緩存值。 --[3]當后端根本沒有返回任何值時,我們應該通過將一些存根值插入緩存來仔細處理。 local function read_cache(key) local ngx_resp = nil -- 獲取共享內存上key對應的值。如果key不存在,或者key已經過期,將會返回nil;如果出現錯誤,那么將會返回nil以及錯誤信息。 -- step 1 local val, err = live_ngx_cache:get(key) if val then if log_switch == 1 then log(ERR, " [1] [read_ngx_cache] content from ngx.cache id = " .. key) -- tag data origin end return val end if err then log(ERR, "failed to get key from shm: ", err) end -- cache miss! -- step 2: local lock, err = resty_lock:new("cache_lock") -- new resty.lock if not lock then log(ERR, "failed to create lock [cache_lock] : ", err) return end local elapsed, err = lock:lock(key) -- 鎖 if not elapsed then log(ERR, "failed to acquire the lock", err) return end -- lock successfully acquired! -- step 3: -- someone might have already put the value into the cache ,so we check it here again: val, err = live_ngx_cache:get(key) if val then local ok, err = lock:unlock() if not ok then log(ERR, "failed to unlock [111] : ", err) end return val end --- step 4: local val = read_redis(redis_host, redis_port, redis_auth, { key }) if not val then local ok, err = lock:unlock() if not ok then log(ERR, "failed to unlock [222] : ", err) end -- FIXME: we should handle the backend miss more carefully -- here, like inserting a stub value into the cache. log(ERR, "[4] ngx.cache find redis cache no value found : ", err) return ngx_resp end -- [lock] update the shm cache with the newly fetched value local ok, err = live_ngx_cache:set(key, val, 1) if not ok then local ok, err = lock:unlock() if not ok then log(ERR, "failed to unlock [333] : ", err) end log(ERR, "failed to update live_ngx_cache: ", err) end local ok, err = lock:unlock() if not ok then log(ERR, "failed to unlock [444] : ", err) end return val end -------------- read_http 大并發采用 resty.http ,對于:ngx.location.capture 慎用 local function read_http(id) local httpc = http.new() local resp, err = httpc:request_uri("https://live.tinywan.com", { method = "GET", path = "/api/live/" .. id, headers = { ["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36" } }) if not resp then log(ERR, "resty.http API request error :", err) return end httpc:close() -- 判斷狀態碼 if resp.status ~= ngx.HTTP_OK then log(ERR, "request error, status :", resp.status) return end if resp.status == ngx.HTTP_FORBIDDEN then log(ERR, "request error, status :", resp.status) return end -- backend not data 判斷api返回的狀態碼 local status_code = helper.cjson_decode(resp.body)['code'] if tonumber(status_code) == 200 then -- 正常數據緩存到 Redis 數據緩存 local live_info_key = "LIVE_TABLE:" .. id local live_value = helper.cjson_decode(resp.body)['data'] -- 解析的Lua自己的然后存儲到Redis 數據庫中去(這里最好使用lua的json格式去寫入) local live_live_str = write_redis(redis_host, redis_port, redis_auth, { live_info_key }, helper.cjson_encode(live_value)) if not live_live_str then log(ERR, "redis set info error: ") end if log_switch == 1 then log(ERR, "[3] [read_http] content from backend API id : " .. id) -- tag data origin end return helper.cjson_encode(live_value) else -- 后端沒有數據直接返回 nil log(ERR, " [read_http] backend API is not content return error_msg : " .. helper.cjson_decode(resp.body)['msg']) -- tag data origin return end end -- 業務邏輯處理 local function read_content(id) local cache_content = nil local live_key = "LIVE:" .. id local content = read_cache(live_key) if not content then log(ERR, "[5] redis not found content, back to backend API , id : ", id) content = read_http(id) end if not content then log(ERR, "backend API not found content, id : ", id) return cache_content end if tostring(content) == "false" then log(ERR, "backend API content is false ", id) return cache_content end return content end local _M = { read_content = read_content } return _M ``` 渲染請求效果 ![](https://img.kancloud.cn/ed/04/ed04e56ca57f1692cb953e71f21dee29_848x588.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看