FreeSWITCH 簡單圖形化界面40 - 使用mod_curl模塊進行http請求
- 0、界面預覽
- 00、簡介
- 1、編譯安裝
- 1.1 編輯模塊配置文件
- 2、使用
- 2.1 撥號規則
- GET 請求
- POST 請求
- JSON 數據
- 2.2 Lua 腳本
- GET 請求
- POST 請求
- JSON 數據
- 3 、示例
- 3.1 示例 1:提交 CDR 到第三方接口
- 3.2 示例 2:提交外呼狀態到第三方接口
0、界面預覽
http://myfs.f3322.net:8020/
用戶名:admin,密碼:admin
FreeSWITCH界面安裝參考:https://blog.csdn.net/jia198810/article/details/137820796
00、簡介
mod_curl
是 FreeSWITCH 的一個強大模塊,它允許用戶通過 HTTP 請求與外部服務進行交互,從而實現數據的獲取和提交。無論是簡單的 GET 請求,還是復雜的 POST 請求和文件傳輸,mod_curl
都能輕松應對。
1、編譯安裝
在使用mod_curl
之前,需要確保該模塊已正確編譯并加載到 FreeSWITCH 中。以下是詳細的編譯和安裝步驟:
1.1 編輯模塊配置文件
- 打開 FreeSWITCH 源代碼目錄下的
modules.conf
文件,找到以下行并取消注釋:
#applications/mod_curl
保存文件并退出。
- 重新編譯 FreeSWITCH
在終端中執行以下命令,重新編譯 FreeSWITCH:
makemake install
- 加載模塊
編輯 FreeSWITCH 的模塊加載配置文件modules.conf.xml
(路勁為/usr/local/freeswitch/conf/autoload_configs
),添加以下內容:
<load module="mod_curl"/>
保存文件后,重新加載 FreeSWITCH 以使模塊生效。
- 驗證模塊加載
啟動 FreeSWITCH 并進入 CLI,執行以下命令以驗證mod_curl
是否已正確加載:
module_exists mod_curl
如果返回true
,則表示模塊加載成功。
2、使用
2.1 撥號規則
mod_curl
提供了兩種主要的應用方式:curl
和curl_sendfile
(不常用)。
在撥號規則中,可以通過以下方式調用curl
應用:
<action application="curl" data="http://example.com/api?param=value"/>
curl應用的請求,會生成兩個通道變量 curl_response_data 和curl_response_code,可以使用${}獲取。
GET 請求
通過 URL 參數發送 GET 請求:
<action application="curl" data="http://example.com/api?param=value"/>
POST 請求
發送 POST 請求并攜帶數據:
<action application="curl" data="http://example.com/api post param=value"/>
JSON 數據
發送 JSON 格式的數據:
<action application="curl" data="http://example.com/api content-type application/json post {\"key\":\"value\"}"/>
2.2 Lua 腳本
mod_curl
也可以在 Lua 腳本中使用,通過 FreeSWITCH 的 API 接口調用 HTTP 請求。
GET 請求
在 Lua 腳本中發起 GET 請求的示例如下:
local api = freeswitch.API()local url = "http://example.com/api?param=value"
local response = api:execute("curl", url)freeswitch.consoleLog("INFO", "Response: " .. response .. "\n")
POST 請求
發送 POST 請求的示例如下:
local api = freeswitch.API()local url = "http://example.com/api"
local data = "param=value"
local response = api:execute("curl", url .. " post " .. data)freeswitch.consoleLog("INFO", "Response: " .. response .. "\n")
JSON 數據
發送 JSON 格式數據的示例如下:
local api = freeswitch.API()local url = "http://example.com/api"
local json_data = "{ \"key\": \"value\" }"
local response = api:execute("curl", url .. " content-type application/json post " .. json_data)freeswitch.consoleLog("INFO", "Response: " .. response .. "\n")
3 、示例
3.1 示例 1:提交 CDR 到第三方接口
在呼叫結束后,將通話詳情記錄(CDR)提交到第三方接口。以下是 Lua 腳本的實現示例:
#!/usr/bin/env lua
-- upload_cdr.lua
-- 2024年6月29日
-- 提交話單信息到第三方接口
-- 撥號規則,提前設置掛機回調
-- session:execute("set", string.format("api_hangup_hook=lua upload_cdr.lua")-- 序列化并打印env對象的所有通話信息,調試專用
-- local call_info = env:serialize()
-- freeswitch.consoleLog("INFO", "所有通話信息:\n" .. call_info)
local mobile = env:getHeader("destination_number") or ""
local caller_ani = env:getHeader("Caller-ANI") or ""
local sip_account = env:getHeader("sip_from_user") or ""
local start_time = env:getHeader("start_stamp") or ""
-- local start_time = env:getHeader("answer_stamp") or ""
local end_time = env:getHeader("end_stamp") or ""
local use_time_length = env:getHeader("billsec") or "0"
local order_no = string.format("freeSWITCH%s%s", sip_account, mobile)
local mobile_hangup_api = env:getHeader("mobile_hangup_api") or ""
local api_timeout = env:getHeader("api_timeout") or "3"-- 打印詳細信息,確保變量不為空
if sip_account == mobile thenfreeswitch.consoleLog("INFO", "異常呼叫主叫=被叫,再次獲取SIP賬號為 : " .. caller_ani .. "\n")sip_account = caller_ani
end
freeswitch.consoleLog("INFO", "CallerANI : " .. caller_ani .. "\n")
freeswitch.consoleLog("INFO", "SIP賬號 : " .. sip_account .. "\n")
freeswitch.consoleLog("INFO", "被叫號碼 : " .. mobile .. "\n")
freeswitch.consoleLog("INFO", "開始時間 : " .. start_time .. "\n")
freeswitch.consoleLog("INFO", "結束時間 : " .. end_time .. "\n")
freeswitch.consoleLog("INFO", "通話時長 : " .. use_time_length .. "\n")
freeswitch.consoleLog("INFO", "訂單號 : " .. order_no .. "\n")
freeswitch.consoleLog("INFO", "CDR推送接口 : " .. mobile_hangup_api .. "\n")
freeswitch.consoleLog("INFO", "接口超時時間 : " .. api_timeout .. "\n")-- 準備執行命令
local api = freeswitch.API();--[[
-- 使用python提交
local cmd = string.format("/usr/local/python310/bin/python /usr/local/freeswitch/scripts/upload_cdr.py '%s' '%s' '%s' '%s' '%s' '%s' '%s'",mobile, sip_account, start_time, end_time, use_time_length, order_no, mobile_hangup_api)
local response = api:execute("bg_system", cmd)
]]-- 使用curl提交
local cmd = string.format("%s connect-timeout %s timeout %s post mobile=%s&sip_account=%s&start_time='%s'&end_time='%s'&use_time_length=%s&order_no=%s",mobile_hangup_api, api_timeout, api_timeout, mobile, sip_account, start_time, end_time, use_time_length, order_no)
freeswitch.consoleLog("INFO", "推送命令: " .. cmd .. "\n")
local response = api:execute("curl", cmd)
if (response == "") thenfreeswitch.consoleLog("INFO", "推送結果: 無響應,可能連接接口失敗!")
elsefreeswitch.consoleLog("INFO", "推送結果: " .. response .. "\n")
end
3.2 示例 2:提交外呼狀態到第三方接口
在外呼結束后,將外呼狀態提交到第三方接口。以下是 Lua 腳本的實現示例:
#!/usr/bin/env lua
-- handle-callout-result.lua
-- 2025年2月26日
-- 處理外呼結果
-- 外呼api設置掛機回調。originate {origination_caller_id_number=300,orgination_caller_id_name=outcall,api_hangup_hook='lua handle-callout-result.lua'}sofia/gateway/gw01/172xxxx2122 401 xml Local-Extensions -- local env
-- local freeswitchlocal call_info = env:serialize()
-- -- 序列化并打印env對象的所有通話信息,調試專用
-- freeswitch.consoleLog("INFO", "所有通話信息:\n" .. call_info)-- 開始時間
local start_time = env:getHeader("start_stamp") or ""-- 結束時間
local end_time = env:getHeader("end_stamp") or ""-- 通話時間
local duration = env:getHeader("billsec") or "0"-- SIP中繼名稱
local trunk_name = env:getHeader("trunk_name") or ""-- 被叫號碼
local destination_number = env:getHeader("destination_number") or ""-- 本地號碼
local local_number = env:getHeader("rdnis") or ""-- 備用被叫號碼
local sip_to_user = env:getHeader("sip_to_user") or ""-- 呼出主叫號碼
local outgoing_caller_id_number = env:getHeader("origination_caller_id_number") or ""-- answer api
local answer_api = env:getHeader("answer_api") or ""-- no_answer api
local no_answer_api = env:getHeader("no_answer_api") or ""-- api 超時時間
local api_timeout = 3-- 通話結果
local hangup_cause = env:getHeader("hangup_cause") or ""-- 是否檢查主叫號碼被占用
local check_number_in_use = env:getHeader("check_number_in_use") or "false"local response
local result
local temp_string-- 打印詳細信息,確保變量不為空
if destination_number == "" thenfreeswitch.consoleLog("INFO", string.format("# destination_number未空,使用sip_to_user的值%s\n",sip_to_user))destination_number = sip_to_user
end
freeswitch.consoleLog("INFO", "# ==============API接口外呼掛機處理============= \n")freeswitch.consoleLog("INFO", "# ------------------外呼呼叫信息---------------- \n")
freeswitch.consoleLog("INFO", "# 開始時間 : " .. start_time .. "\n")
freeswitch.consoleLog("INFO", "# 結束時間 : " .. end_time .. "\n")
freeswitch.consoleLog("INFO", "# 通話時長 : " .. duration .. "\n")
freeswitch.consoleLog("INFO", "# 外呼號碼 : " .. destination_number .. "\n")
freeswitch.consoleLog("INFO", "# 本地號碼 : " .. local_number .. "\n")
freeswitch.consoleLog("INFO", "# 呼出主叫 : " .. outgoing_caller_id_number .. "\n")
freeswitch.consoleLog("INFO", "# 掛機接口 : " .. no_answer_api .. "\n")
freeswitch.consoleLog("INFO", "# ---------------------------------------------\n\n")-- 執行fs api命令
local api = freeswitch.API();-- 應答提交api,在401 xml Local-Extensions中。
-- if (hangup_cause == "ANSWER" or hangup_cause == "NORMAL_CLEARING") then
-- -- 呼叫應答提交
-- freeswitch.consoleLog("INFO", "# 呼叫結果 : 呼叫已經應答,推送應答接口\n")
-- if (answer_api == "") then
-- freeswitch.consoleLog("INFO", "# 推送結果 : 應答接口為空,不提交!\n")
-- return
-- else
-- -- 提交無應答結果
-- temp_string = string.format(
-- "%s connect-timeout %s timeout %s post destination_number=%s",
-- no_answer_api, api_timeout, api_timeout, destination_number)
-- freeswitch.consoleLog("INFO", string.format("# 推送結果 : 請求地址:%s\n",temp_string))-- -- 執行推送
-- response = api:execute("curl",temp_string)
-- if (response == "") then
-- freeswitch.consoleLog("INFO", "# 推送結果 : 接口無響應,可能連接接口失敗!\n")
-- else
-- freeswitch.consoleLog("INFO", "# 推送結果 : " .. response .. "\n")
-- end
-- endfreeswitch.consoleLog("INFO", "# ----------------外呼掛機處理-----------------\n")if (hangup_cause == "BUSY" or hangup_cause == "USER_BUSY" or hangup_cause == "NO_USER_RESPONSE" or hangup_cause == "NO_ROUTE_DESTINATION" or hangup_cause == "CALL_REJECTED" or hangup_cause == "NO_ANSWER") thenfreeswitch.consoleLog("INFO", "# 掛機結果 : " .. hangup_cause .. "\n")-- 呼叫未應答提交freeswitch.consoleLog("INFO", "# 呼叫結果 : 呼叫未應答,推送未應答接口\n")if (no_answer_api == "") thenfreeswitch.consoleLog("INFO", "# 推送結果 : 未應答接口為空,不提交!\n")returnelse-- 提交無應答結果temp_string = string.format("%s content-type application/json connect-timeout %s timeout %s post {\"destination_number\":\"%s\"}",no_answer_api, api_timeout, api_timeout, destination_number)freeswitch.consoleLog("INFO", string.format("# 推送結果 : 請求地址:%s\n",temp_string))-- 執行推送response = api:execute("curl", temp_string)if (response == "") thenfreeswitch.consoleLog("INFO", "# 推送結果 : 接口無響應,可能連接接口失敗!\n")elsefreeswitch.consoleLog("INFO", "# 推送結果 : ".. response.. "\n")endend
elseif (hangup_cause == "NORMAL_CLEARING") thenfreeswitch.consoleLog("INFO", "# 掛機結果 : " .. hangup_cause .. "\n")freeswitch.consoleLog("INFO", "# 掛機結果 : 通話正常掛斷\n")
elsefreeswitch.consoleLog("INFO", "# 掛機結果 : " .. hangup_cause .. "\n")
end
freeswitch.consoleLog("INFO", "# ----------------------------------------------\n")-- 如果要檢查主叫號碼是否被占用,則呼叫結束后,刪除正在使用的主叫號碼
if (check_number_in_use == "true") thenfreeswitch.consoleLog("INFO", string.format("# 通話已結束 : 開啟了檢查主叫號碼占用,將釋放主叫%s\n",outgoing_caller_id_number))-- 檢查號碼是否被占用temp_string = string.format("delete/%s/number_in_use_%s",trunk_name, outgoing_caller_id_number)freeswitch.consoleLog("INFO", string.format("# 通話已結束 : 釋放正在使用的主叫號碼:%s\n",temp_string))result = api:execute("hash",temp_string)freeswitch.consoleLog("INFO", string.format("# 通話已結束 : 釋放正在使用的主叫號碼:%s\n",result))
end
freeswitch.consoleLog("INFO", "# ===============================================\n\n")
return
祝君好運