氧气是建在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对象列为中的结构 |
将请求的身体置于朱莉娅结构中