氧氣是建在HTTP.JL庫頂上的微型框架。呼吸輕鬆知道您可以使用您已經熟悉的抽象來快速旋轉Web服務器。
需要幫助嗎?隨時在我們的社交媒體渠道上接觸。
pkg > add Oxygen創建一個具有很少的代碼行的網絡服務器
using Oxygen
using HTTP
@get " /greet " function (req :: HTTP.Request )
return " hello world! "
end
# start the web server
serve ()處理程序用於以乾淨直接的方式將您的代碼連接到服務器。他們將URL分配給函數並在傳入請求匹配該URL時調用該功能。
do..endRequest處理程序有3種類型的受支持的處理程序:
Request處理程序Stream處理程序Websocket處理程序 using HTTP
using Oxygen
# Request Handler
@get " / " function (req :: HTTP.Request )
...
end
# Stream Handler
@stream " /stream " function (stream :: HTTP.Stream )
...
end
# Websocket Handler
@websocket " /ws " function (ws :: HTTP.WebSocket )
...
end它們只是功能,這意味著可以表達和定義多種方式。以下是您可以表達和分配Request處理程序的幾種不同方式的示例。
@get " /greet " function ()
" hello world! "
end
@get ( " /gruessen " ) do
" Hallo Welt! "
end
@get " /saluer " () -> begin
" Bonjour le monde! "
end
@get " /saludar " () -> " ¡Hola Mundo! "
@get " /salutare " f () = " ciao mondo! "
# This function can be declared in another module
function subtract (req, a :: Float64 , b :: Float64 )
return a - b
end
# register foreign request handlers like this
@get " /subtract/{a}/{b} " subtract請求處理程序用於處理HTTP請求。它們是使用宏或其函數當量定義的,並接受HTTP.Request對像作為第一個參數。這些處理程序支持函數和doblock語法。
@get , @post , @put , @patch , @delete , @routeget() , post() , put() , patch() , delete() , route()流處理程序用於流數據。它們是使用@stream宏或stream()函數定義的,並接受HTTP.Stream對像作為第一個參數。這些處理程序支持函數和doblock語法。
@stream和stream()不需要第一個參數上的類型定義,他們假定它是流。Stream操作員: @get , @post post等Stream處理程序WebSocket處理程序用於處理WebSocket連接。它們是使用@websocket宏或websocket()函數定義的,並接受HTTP.WebSocket對像作為第一個參數。這些處理程序支持函數和doblock語法。
@websocket和websocket()不需要在第一個參數上進行類型定義,他們假定它是Websocket。Websocket處理程序也可以使用@get Macro或get()函數分配,因為WebSocket協議需要GET請求來啟動握手。Websocket 註冊您的請求處理程序有兩種主要方法:使用Doblock語法的標準路由宏或路由功能。
對於每個路由宏,我們現在都有一個等效的路由功能
@get -> get ()
@post -> post ()
@put -> put ()
@patch -> patch ()
@delete -> delete ()
@route -> route ()兩者之間的唯一實際區別在於,在預譯階段調用路由宏,而路由函數僅在調用時才調用。 (路由宏調用引擎蓋下的路由功能)
# Routing Macro syntax
@get " /add/{x}/{y} " function (request :: HTTP.Request , x :: Int , y :: Int )
x + y
end
# Routing Function syntax
get ( " /add/{x}/{y} " ) do request :: HTTP.Request , x :: Int , y :: Int
x + y
end 默認情況下,氧氣自動從請求處理程序構建響應時自動標識返回值的內容類型。該默認功能非常有用,但是確實會對性能產生影響。在已知返回類型的情況下,建議使用預先存在的渲染功能之一來加快速度。
這是當前支持的渲染功能的列表: html , text , json , file , xml , js , css , binary
以下是如何使用這些功能的示例:
using Oxygen
get ( " /html " ) do
html ( " <h1>Hello World</h1> " )
end
get ( " /text " ) do
text ( " Hello World " )
end
get ( " /json " ) do
json ( Dict ( " message " => " Hello World " ))
end
serve ()在大多數情況下,這些功能接受普通字符串作為輸入。唯一的例外是接受Vector{UInt8} binary函數,並且接受任何可序列化類型的json函數。
路徑參數用括號聲明,並直接傳遞給您的請求處理程序。
using Oxygen
# use path params without type definitions (defaults to Strings)
@get " /add/{a}/{b} " function (req, a, b)
return parse (Float64, a) + parse (Float64, b)
end
# use path params with type definitions (they are automatically converted)
@get " /multiply/{a}/{b} " function (req, a :: Float64 , b :: Float64 )
return a * b
end
# The order of the parameters doesn't matter (just the name matters)
@get " /subtract/{a}/{b} " function (req, b :: Int64 , a :: Int64 )
return a - b
end
# start the web server
serve ()查詢參數可以直接在處理程序簽名內部聲明。路由路徑內未提及的任何參數都被認為是查詢參數。
@get " /query " function (req :: HTTP.Request , a :: Int , message :: String = " hello world " )
return (a, message)
end另外,您可以使用queryparams()函數從URL中提取原始值作為字典。
@get " /query " function (req :: HTTP.Request )
return queryparams (req)
end 使用formdata()函數從請求正文中提取和解析表單數據。此功能從表單中返回鍵值對的字典
using Oxygen
# Setup a basic form
@get " / " function ()
html ( """
<form action="/form" method="post">
<label for="firstname">First name:</label><br>
<input type="text" id="firstname" name="firstname"><br>
<label for="lastname">Last name:</label><br>
<input type="text" id="lastname" name="lastname"><br><br>
<input type="submit" value="Submit">
</form>
""" )
end
# Parse the form data and return it
@post " /form " function (req)
data = formdata (req)
return data
end
serve ()所有對像都會使用JSON3庫自動將其供應到JSON
using Oxygen
using HTTP
@get " /data " function (req :: HTTP.Request )
return Dict ( " message " => " hello! " , " value " => 99.3 )
end
# start the web server
serve ()氧氣為大多數對象提供了一些開箱即用的序列化和避難所化,但在轉換結構時需要使用結構型
using Oxygen
using HTTP
using StructTypes
struct Animal
id :: Int
type :: String
name :: String
end
# Add a supporting struct type definition so JSON3 can serialize & deserialize automatically
StructTypes . StructType ( :: Type{Animal} ) = StructTypes . Struct ()
@get " /get " function (req :: HTTP.Request )
# serialize struct into JSON automatically (because we used StructTypes)
return Animal ( 1 , " cat " , " whiskers " )
end
@post " /echo " function (req :: HTTP.Request )
# deserialize JSON from the request body into an Animal struct
animal = json (req, Animal)
# serialize struct back into JSON automatically (because we used StructTypes)
return animal
end
# start the web server
serve ()氧氣配有幾種內置提取器,旨在減少序列化輸入到處理程序功能所需的樣板量。通過簡單地定義結構並指定數據源,這些提取器通過統一的API簡化了數據攝入和驗證的過程。
payload屬性訪問序列化數據@kwdef宏定義時可以分配默認值支持提取器:
Path - 從路徑參數提取Query - 從查詢參數提取,Header - 從請求標題提取Form - 從請求主體中提取數據Body - 將整個請求主體序列到給定類型(字符串,float64等)。ProtoBuffer從請求主體中提取ProtoBuf消息(可通過軟件包擴展提供)Json從請求正文中提取JSONJsonFragment使用參數名稱提取JSON主體的“片段”,以識別和提取相應的頂級鍵在此示例中,我們表明可以與常規路徑參數一起使用Path提取器。這也可與常規查詢參數和Query提取器一起使用。
struct Add
b :: Int
c :: Int
end
@get " /add/{a}/{b}/{c} " function (req, a :: Int , pathparams :: Path{Add} )
add = pathparams . payload # access the serialized payload
return a + add . b + add . c
end 可以使用@kwdef宏來設置默認值。
@kwdef struct Pet
name :: String
age :: Int = 10
end
@post " /pet " function (req, params :: Json{Pet} )
return params . payload # access the serialized payload
end 除了序列化數據之外,您還可以使用validate函數來定義自己的驗證規則。在下面的示例中,我們顯示瞭如何在代碼中同時使用global和local驗證器。
local驗證器之前調用global驗證器。 import Oxygen : validate
struct Person
name :: String
age :: Int
end
# Define a global validator
validate (p :: Person ) = p . age >= 0
# Only the global validator is ran here
@post " /person " function (req, newperson :: Json{Person} )
return newperson . payload
end
# In this case, both global and local validators are ran (this also makes sure the person is age 21+)
# You can also use this sytnax instead: Json(Person, p -> p.age >= 21)
@post " /adult " function (req, newperson = Json {Person} (p -> p . age >= 21 ))
return newperson . payload
end 您可以將變量直接插入路徑,這使動態註冊路線變得輕而易舉
(感謝@anandijain的想法)
using Oxygen
operations = Dict ( " add " => + , " multiply " => * )
for (pathname, operator) in operations
@get " / $pathname /{a}/{b} " function (req, a :: Float64 , b :: Float64 )
return operator (a, b)
end
end
# start the web server
serve ()router()函數是一個HOF(高階函數),它允許您在多個端點上重複使用相同的路徑前綴和屬性。當您的API開始增長並且您想保持路徑操作組織時,這很有幫助。
以下是router()函數可以採用的參數:
router (prefix :: String ; tags :: Vector , middleware :: Vector , interval :: Real , cron :: String )tags - 用於組織自動化文檔中的端點middleware - 用於設置路由器和特定路由的中間件interval - 用於支持重複操作(以秒為單位呼叫請求處理程序)cron用於指定確定何時調用請求處理程序的cron表達式。 using Oxygen
# Any routes that use this router will be automatically grouped
# under the 'math' tag in the autogenerated documenation
math = router ( " /math " , tags = [ " math " ])
# You can also assign route specific tags
@get math ( " /multiply/{a}/{b} " , tags = [ " multiplication " ]) function (req, a :: Float64 , b :: Float64 )
return a * b
end
@get math ( " /divide/{a}/{b} " ) function (req, a :: Float64 , b :: Float64 )
return a / b
end
serve ()氧氣帶有一個內置的CRON調度系統,可讓您在CRON表達式匹配當前時間時自動調用端點和功能。
安排作業後,將創建一個新任務並在後台運行。每個任務都使用其給定的cron表達式和當前時間來確定在執行之前需要多長時間入睡。
氧氣中的Cron解析器基於與彈簧中使用的規格相同的規格。您可以在春季cron表達式頁面上找到有關此信息的更多信息。
以下是我們cron表達式中每個參數所代表的內容的分解。雖然我們的規範與Spring定義的規格非常相似,但這並不是確切的1比1匹配。
The string has six single space-separated time and date fields:
┌───────────── second (0-59)
│ ┌───────────── minute (0 - 59)
│ │ ┌───────────── hour (0 - 23)
│ │ │ ┌───────────── day of the month (1 - 31)
│ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC)
│ │ │ │ │ ┌───────────── day of the week (1 - 7)
│ │ │ │ │ │ (Monday is 1, Tue is 2... and Sunday is 7)
│ │ │ │ │ │
* * * * * *
還支持部分錶達式,這意味著可以遺漏後續的表達式(它們默認為'*' )。
# In this example we see only the `seconds` part of the expression is defined.
# This means that all following expressions are automatically defaulted to '*' expressions
@cron " */2 " function ()
println ( " runs every 2 seconds " )
endrouter()函數具有稱為cron的關鍵字參數,該參數接受CRON表達式,該表達式確定何時調用端點。就像其他關鍵字參數一樣,可以通過共享路由器或被繼承的端點覆蓋的端點重複使用。
# execute at 8, 9 and 10 o'clock of every day.
@get router ( " /cron-example " , cron = " 0 0 8-10 * * * " ) function (req)
println ( " here " )
end
# execute this endpoint every 5 seconds (whenever current_seconds % 5 == 0)
every5 = router ( " /cron " , cron = " */5 " )
# this endpoint inherits the cron expression
@get every5 ( " /first " ) function (req)
println ( " first " )
end
# Now this endpoint executes every 2 seconds ( whenever current_seconds % 2 == 0 ) instead of every 5
@get every5 ( " /second " , cron = " */2 " ) function (req)
println ( " second " )
end除了調度端點外,您還可以使用新的@cron宏來安排功能。如果您想在特定時間運行代碼而不使其在API中可見或可召喚,這將很有用。
@cron " */2 " function ()
println ( " runs every 2 seconds " )
end
@cron " 0 0/30 8-10 * * * " function ()
println ( " runs at 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day " )
end當您運行serve()或serveparallel()時,所有註冊的CRON作業將自動啟動。如果服務器被停止或殺死,則所有運行工作也將被終止。您可以通過調用terminate()函數或使用ctrl+C手動殺死服務器來停止服務器和所有重複任務和CRON作業。
此外,氧氣還提供了實用程序功能,可以手動啟動和停止Cron Jobs: startcronjobs()和stopcronjobs() 。這些功能也可以在Web服務器之外使用。
重複任務提供了一個簡單的API,可以在設置間隔內運行功能。
有兩種註冊重複任務的方法:
interval參數router()@repeat宏重要的是要注意,使用此屬性的請求處理程序無法在默認的HTTP.Request參數之外定義其他功能參數。
在下面的示例中,每0.5秒調用/repeat/hello端點,每次將"hello"打印到控制台。
router()函數具有一個interval參數,該參數用於以設置間隔(以秒為單位)調用請求處理程序。
using Oxygen
taskrouter = router ( " /repeat " , interval = 0.5 , tags = [ " repeat " ])
@get taskrouter ( " /hello " ) function ()
println ( " hello " )
end
# you can override properties by setting route specific values
@get taskrouter ( " /bonjour " , interval = 1.5 ) function ()
println ( " bonjour " )
end
serve ()以下是如何在路由器之外註冊重複任務的示例
@repeat 1.5 function ()
println ( " runs every 1.5 seconds " )
end
# you can also "name" a repeat task
@repeat 5 " every-five " function ()
println ( " runs every 5 seconds " )
end當服務器運行時,所有任務均自動啟動。但是該模塊還提供了實用程序,可以使用以下功能對運行任務進行更細粒度的控制: starttasks() , stoptasks()和cleartasks()
氧氣可以與修訂融合以提供熱加載,從而加快開發的速度。由於修訂建議將所有代碼保留在包裝中,因此您首先需要轉到此類佈局。
首先確保您的Project.toml具有所需的字段,例如可以在軟件包而不是項目上使用的name 。
接下來,在模塊src/MyModule.jl中為您的路由編寫主要代碼:
module MyModule
using Oxygen; @oxidise
@get "/greet" function(req::HTTP.Request)
return "hello world!"
end
end
然後,您可以進行debug.jl入口點腳本:
using Revise
using Oxygen
using MyModule
MyModule.serve(revise=:eager)
revise選項也可以設置為:lazy ,在這種情況下,修訂將始終留在請求之前,而不是在源文件在磁盤上更改時熱切嘗試。
請注意,您應該在沒有生產中修改的情況下運行另一個入門點腳本。
在某些高級方案中,您可能需要在不同端口的同一模塊中旋轉多個Web速度。氧氣提供了創建Web服務器多個實例的靜態和動態方法。
作為一般的經驗法則,如果您知道提前需要多少個實例,最好採用靜態方法。
@oxidise的多個實例氧提供了一個新的宏,可以設置和運行多個實例。它生成方法並將其綁定到當前模塊的新內部狀態。
在下面的示例中,在模塊A和B中定義了兩個簡單的服務器,並在父模塊中啟動。兩個模塊都包含從氧氣導出的所有功能,可以直接調用,如下所示。
module A
using Oxygen; @oxidise
get ( " / " ) do
text ( " server A " )
end
end
module B
using Oxygen; @oxidise
get ( " / " ) do
text ( " server B " )
end
end
try
# start both instances
A . serve (port = 8001 , async = true )
B . serve (port = 8002 , async = false )
finally
# shut down if we `Ctrl+C`
A . terminate ()
B . terminate ()
endinstance()的多個實例為instance函數可幫助您在運行時創建氧Web服務器的完全獨立的實例。它通過在運行時動態創建朱莉婭模塊並在其中加載氧代碼來起作用。
來自氧氣的所有相同方法均在命名實例下可用。在下面的示例中,我們可以使用get ,並簡單地使用app1變量上的點serve來訪問基礎方法。
using Oxygen
# ######## Setup the first app #########
app1 = instance ()
app1 . get ( " / " ) do
text ( " server A " )
end
# ######## Setup the second app #########
app2 = instance ()
app2 . get ( " / " ) do
text ( " server B " )
end
# ######## Start both instances #########
try
# start both servers together
app1 . serve (port = 8001 , async = true )
app2 . serve (port = 8002 )
finally
# clean it up
app1 . terminate ()
app2 . terminate ()
end 對於需要處理更高量流量的情況,您可以在多線程模式下運行氧氣。為了利用此模式,朱莉婭必須有超過1個線程可以使用。您可以使用以下命令開始使用4個線程的朱莉婭會話
julia --threads 4 serveparallel()以流式傳輸模式啟動Web服務器,並以合作多任務處理方式處理請求。此功能使用Threads.@spawn來安排任何可用線程的新任務。同時,調用每個請求處理程序時,在此任務中使用@ASYNC。這允許任務在I/O操作過程中產生。
using Oxygen
using StructTypes
using Base . Threads
# Make the Atomic struct serializable
StructTypes . StructType ( :: Type{Atomic{Int64}} ) = StructTypes . Struct ()
x = Atomic {Int64} ( 0 );
@get " /show " function ()
return x
end
@get " /increment " function ()
atomic_add! (x, 1 )
return x
end
# start the web server in parallel mode
serveparallel ()氧氣包括Protobuf.jl軟件包的擴展。該擴展名提供了一個protobuf()函數,簡化了在Web服務器上下文中使用協議緩衝區的過程。要更好地了解此軟件包,請參考其官方文檔。
此功能在以下方案中具有過載:
using HTTP
using ProtoBuf
using Oxygen
# The generated classes need to be created ahead of time (check the protobufs)
include ( " people_pb.jl " );
using . people_pb : People, Person
# Decode a Protocol Buffer Message
@post " /count " function (req :: HTTP.Request )
# decode the request body into a People object
message = protobuf (req, People)
# count the number of Person objects
return length (message . people)
end
# Encode & Return Protocol Buffer message
@get " /get " function ()
message = People ([
Person ( " John Doe " , 20 ),
Person ( " Alice " , 30 ),
Person ( " Bob " , 35 )
])
# seralize the object inside the body of a HTTP.Response
return protobuf (message)
end以下是用於創建必要的Julia綁定的模式的示例。這些綁定允許在上面的示例中對消息進行編碼和解碼。
syntax = "proto3" ;
message Person {
string name = 1 ;
sint32 age = 2 ;
}
message People {
repeated Person people = 1 ;
}氧氣配備了幾個包裝擴展,可增強其繪圖功能。這些擴展使直接從請求處理程序返回地塊變得易於返回。所有操作均使用IOBUFFER進行內存,然後返回HTTP.Response
支持的軟件包及其助手用戶:
png , svg , pdf , htmlhtmlhtml using CairoMakie : heatmap
using Oxygen
@get " /cairo " function ()
fig, ax, pl = heatmap ( rand ( 50 , 50 ))
png (fig)
end
serve () using Bonito
using WGLMakie : heatmap
using Oxygen
using Oxygen : html # Bonito also exports html
@get " /wgl " function ()
fig = heatmap ( rand ( 50 , 50 ))
html (fig)
end
serve () using Bonito
using WGLMakie : heatmap
using Oxygen
using Oxygen : html # Bonito also exports html
@get " /bonito " function ()
app = App () do
return DOM . div (
DOM . h1 ( " Random 50x50 Heatmap " ),
DOM . div ( heatmap ( rand ( 50 , 50 )))
)
end
return html (app)
end
serve ()氧氣沒有為模板或添加其他依賴項構建內部發動機,而是提供兩個包裝擴展,以支持Mustache.jl和OteraEngine.jl模板。
氧氣圍繞兩個軟件包提供了一個簡單的包裝API,這使得從字符串,模板和文件中渲染模板很容易。此包裝器API返回render函數,該功能接受輸入字典以填寫模板。
在所有情況下,渲染模板都在HTTP中返回。響應對象準備由API提供。默認情況下,通過查看模板的內容或文件上的擴展名來自動檢測MIME類型。如果您知道MIME類型,則可以直接通過mime_type關鍵字參數傳遞以跳過檢測過程。
請查看小鬍子。 JL文檔以了解包裝的完整功能
示例1:從文件渲染鬍鬚模板
using Mustache
using Oxygen
# Load the Mustache template from a file and create a render function
render = mustache ( " ./templates/greeting.txt " , from_file = false )
@get " /mustache/file " function ()
data = Dict ( " name " => " Chris " )
return render (data) # This will return an HTML.Response with the rendered template
end示例2:為普通字符串鬍子模板指定MIME類型
using Mustache
using Oxygen
# Define a Mustache template (both plain strings and mustache templates are supported)
template_str = " Hello, {{name}}! "
# Create a render function, specifying the MIME type as text/plain
render = mustache (template_str, mime_type = " text/plain " ) # mime_type keyword arg is optional
@get " /plain/text " function ()
data = Dict ( " name " => " Chris " )
return render (data) # This will return a plain text response with the rendered template
end請查看oteraengine.jl文檔,以了解包裝的全部功能
示例1:使用邏輯和循環渲染Otera模板
using OteraEngine
using Oxygen
# Define an Otera template
template_str = """
<html>
<head><title>{{ title }}</title></head>
<body>
{% for name in names %}
Hello {{ name }}<br>
{% end %}
</body>
</html>
"""
# Create a render function for the Otera template
render = otera (template_str)
@get " /otera/loop " function ()
data = Dict ( " title " => " Greetings " , " names " => [ " Alice " , " Bob " , " Chris " ])
return render (data) # This will return an HTML.Response with the rendered template
end在此示例中,使用一個循環的前面定義了一個Otera模板,該模板在名稱列表上迭代,向每個名稱打招呼。
示例2:在Otera模板中運行Julia代碼
using OteraEngine
using Oxygen
# Define an Otera template with embedded Julia code
template_str = """
The square of {{ number }} is {< number^2 >}.
"""
# Create a render function for the Otera template
render = otera (template_str)
@get " /otera/square " function ()
data = Dict ( " number " => 5 )
return render (data) # This will return an HTML.Response with the rendered template
end
在此示例中,使用嵌入式朱莉婭代碼定義了一個Otera模板,該模板計算給定數字的平方。
您可以使用此方便的功能安裝靜態文件,該功能將文件夾遞歸搜索文件並安裝所有內容。所有文件都將啟動時加載到內存中。
using Oxygen
# mount all files inside the "content" folder under the "/static" path
staticfiles ( " content " , " static " )
# start the web server
serve ()與StaticFiles類似,此功能安裝了每個路徑並重新閱讀每個請求的文件。這意味著將顯示服務器啟動後對文件的任何更改。
using Oxygen
# mount all files inside the "content" folder under the "/dynamic" path
dynamicfiles ( " content " , " dynamic " )
# start the web server
serve ()禁用內部記錄儀可以提供一些巨大的性能增長,這在某些情況下可能會有所幫助。有趣的是,我在serve()中看到了2-3倍的速度,在serveparallel()性能中都有4-5倍的速度。
# This is how you disable internal logging in both modes
serve (access_log = nothing )
serveparallel (access_log = nothing )氧氣提供了默認的記錄格式,但允許您使用access_log參數自定義格式。該功能在serve()和serveparallel()函數中都可以使用。
您可以在此處閱讀有關記錄選項的更多信息
# Uses the default logging format
serve ()
# Customize the logging format
serve (access_log = logfmt " [$time_iso8601] " $request " $status " )
# Disable internal request logging
serve (access_log = nothing )中間件功能使創建自定義工作流程以攔截所有傳入請求和響應變得容易。它們的執行方式與通過(從左到右)傳遞的順序執行。
可以使用middleware關鍵字參數在應用程序,路由器和路由層設置它們。所有中間件都是加性的,這些層中定義的任何中間件都將被合併和執行。
中間件將始終按以下順序執行:
application -> router -> route
現在讓我們看看一些中間件的行動:
using Oxygen
using HTTP
const CORS_HEADERS = [
" Access-Control-Allow-Origin " => " * " ,
" Access-Control-Allow-Headers " => " * " ,
" Access-Control-Allow-Methods " => " POST, GET, OPTIONS "
]
# https://juliaweb.github.io/HTTP.jl/stable/examples/#Cors-Server
function CorsMiddleware (handler)
return function (req :: HTTP.Request )
println ( " CORS middleware " )
# determine if this is a pre-flight request from the browser
if HTTP . method (req) == " OPTIONS "
return HTTP . Response ( 200 , CORS_HEADERS)
else
return handler (req) # passes the request to the AuthMiddleware
end
end
end
function AuthMiddleware (handler)
return function (req :: HTTP.Request )
println ( " Auth middleware " )
# ** NOT an actual security check ** #
if ! HTTP . headercontains (req, " Authorization " , " true " )
return HTTP . Response ( 403 )
else
return handler (req) # passes the request to your application
end
end
end
function middleware1 (handle)
function (req)
println ( " middleware1 " )
handle (req)
end
end
function middleware2 (handle)
function (req)
println ( " middleware2 " )
handle (req)
end
end
# set middleware at the router level
math = router ( " math " , middleware = [middleware1])
# set middleware at the route level
@get math ( " /divide/{a}/{b} " , middleware = [middleware2]) function (req, a :: Float64 , b :: Float64 )
return a / b
end
# set application level middleware
serve (middleware = [CorsMiddleware, AuthMiddleware])如果您不想使用氧氣的默認響應序列化器,則可以將其關閉並添加!只需創建自己的特殊中間件功能即可序列化響應並將其添加到您自己的中間件鏈的末尾。
serve()和serveparallel()都有一個serialize關鍵字參數,可以切換默認序列化器。
using Oxygen
using HTTP
using JSON3
@get " /divide/{a}/{b} " function (req :: HTTP.Request , a :: Float64 , b :: Float64 )
return a / b
end
# This is just a regular middleware function
function myserializer (handle)
function (req)
try
response = handle (req)
# convert all responses to JSON
return HTTP . Response ( 200 , [], body = JSON3 . write (response))
catch error
@error " ERROR: " exception = (error, catch_backtrace ())
return HTTP . Response ( 500 , " The Server encountered a problem " )
end
end
end
# make sure 'myserializer' is the last middleware function in this list
serve (middleware = [myserializer], serialize = false )Swagger文檔將自動為您在應用程序中註冊的每條路由生成。默認情況下,僅為您創建路由名稱,參數類型和200和500響應。
您可以在/docs中查看生成的文檔,並且可以在/docs/schema下找到架構。這兩個值都可以使用configdocs()函數更改為您想要的任何內容。您還可以通過在啟動應用程序之前撥打disabledocs()函數來完全退出自動化文檔。
要添加其他詳細信息,您可以使用內置的mergeschema()或setschema()函數直接修改模式自己或從SwaggerMarkdown.jl軟件包中合併生成的模式(我建議後者)
以下是如何合併從SwaggerMarkdown.jl軟件包生成的架構的示例。
using Oxygen
using SwaggerMarkdown
# Here's an example of how you can merge autogenerated docs from SwaggerMarkdown.jl into your api
@swagger """
/divide/{a}/{b}:
get:
description: Return the result of a / b
parameters:
- name: a
in: path
required: true
description: this is the value of the numerator
schema:
type : number
responses:
'200':
description: Successfully returned an number.
"""
@get " /divide/{a}/{b} " function (req, a :: Float64 , b :: Float64 )
return a / b
end
# title and version are required
info = Dict ( " title " => " My Demo Api " , " version " => " 1.0.0 " )
openApi = OpenAPI ( " 3.0 " , info)
swagger_document = build (openApi)
# merge the SwaggerMarkdown schema with the internal schema
mergeschema (swagger_document)
# start the web server
serve ()以下是如何手動修改模式的示例
using Oxygen
using SwaggerMarkdown
# Only the basic information is parsed from this route when generating docs
@get " /multiply/{a}/{b} " function (req, a :: Float64 , b :: Float64 )
return a * b
end
# Here's an example of how to update a part of the schema yourself
mergeschema ( " /multiply/{a}/{b} " ,
Dict (
" get " => Dict (
" description " => " return the result of a * b "
)
)
)
# Here's another example of how to update a part of the schema yourself, but this way allows you to modify other properties defined at the root of the schema (title, summary, etc.)
mergeschema (
Dict (
" paths " => Dict (
" /multiply/{a}/{b} " => Dict (
" get " => Dict (
" description " => " return the result of a * b "
)
)
)
)
) @get (path, func)| 範圍 | 類型 | 描述 |
|---|---|---|
path | string或router() | 必需的。註冊的路線 |
func | function | 必需的。該路線的請求處理程序 |
用於將函數註冊到特定端點以處理該請求的相應類型
@route (methods, path, func)| 範圍 | 類型 | 描述 |
|---|---|---|
methods | array | 必需的。 HTTP請求的類型註冊到此路線 |
path | string或router() | 必需的。註冊的路線 |
func | function | 必需的。該路線的請求處理程序 |
低級宏,允許路由可以處理多種請求類型
staticfiles (folder, mount)| 範圍 | 類型 | 描述 |
|---|---|---|
folder | string | 必需的。從中提供文件的文件夾 |
mountdir | string | 在下方的端點端點(默認為“靜態”) |
set_headers | function | 返回這些文件時自定義HTTP響應標頭 |
loadfile | function | 加載文件時自定義行為 |
在文件夾中使用所有靜態文件。此功能遞歸搜索目錄,並使用其相對路徑將所有文件安裝在MOUNT目錄下方。
dynamicfiles (folder, mount)| 範圍 | 類型 | 描述 |
|---|---|---|
folder | string | 必需的。從中提供文件的文件夾 |
mountdir | string | 在下方的端點端點(默認為“靜態”) |
set_headers | function | 返回這些文件時自定義HTTP響應標頭 |
loadfile | function | 加載文件時自定義行為 |
在文件夾中使用所有靜態文件。此功能遞歸搜索目錄,並使用其相對路徑將所有文件安裝在MOUNT目錄下方。該文件在每個請求上加載,可能會拾取任何文件更改。
html (content, status, headers)| 範圍 | 類型 | 描述 |
|---|---|---|
content | string | 必需的。將返回為HTML的字符串 |
status | integer | HTTP響應代碼(默認為200) |
headers | dict | HTTP響應的標題(默認值的內容類型標頭設置為“ text/html; charset = utf-8”) |
輔助功能以指定何時應返回內容為HTML
queryparams (request)| 範圍 | 類型 | 描述 |
|---|---|---|
req | HTTP.Request | 必需的。 HTTP請求對象 |
從請求返回查詢參數作為dict()
text (request)| 範圍 | 類型 | 描述 |
|---|---|---|
req | HTTP.Request | 必需的。 HTTP請求對象 |
返回請求的主體作為字符串
binary (request)| 範圍 | 類型 | 描述 |
|---|---|---|
req | HTTP.Request | 必需的。 HTTP請求對象 |
返回請求的正文作為二進製文件(返回UInt8 s的向量)
json (request, classtype)| 範圍 | 類型 | 描述 |
|---|---|---|
req | HTTP.Request | 必需的。 HTTP請求對象 |
classtype | struct | 一個將JSON對象列為中的結構 |
將請求的身體置於朱莉婭結構中