UDN
Search public documentation:

WebServerCH
English Translation
日本語訳
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 主页 > 输入 / 输出 > 网络服务器

网络服务器


_文档概述:描述了 UT3 中实现的 HTTP WebServer(网络服务器)的应用及它的 API。

文档变更记录:由 Michiel Hendricks 发表的内容。

概述


该文档将会介绍如何使用 Web Server(网络服务器)以及如何创建新的 Web Application(网络应用程序)。对于供 webserver 使用的网络连接的底层基础信息,请参照 TcpLink 页面。

本文档假设您已经具备了 HTTP 协议方面的基本知识。这里不需要您知道关于 HTTP 的详细信息,但是懂得一些基本信息还是有帮助的。

Webserver(网络服务器)仅支持 HTTP 协议的一个子集。但是网络应用程序可以扩展这个功能。它仅支持 GET 和 POST 请求。

结构


以下类构成了网络服务器的功能:

WebServer
这是网络服务器的入口点,它可以管理连接和应用程序。
WebConnection
这个类是网络服务器的 acceptor 类。对于每个连接到网络服务器的客户端来说,都会创建一个这个类的实例。它管理连接并且再把请求传向网络应用程序之前对其进行预处理。
WebRequest
这个类包含了网络服务器接收到的 HTTP 请求。
WebResponse
这个类实现了给请求提供响应的功能。
WebApplication
这个类的实现负责处理请求并产生响应。当使用网络服务器时,这是您将要扩展的类。

HTTP 请求处理


  1. 客户端可以连接到这个网络服务器。
  2. 创建一个新的 WebConnection(网络连接)WebServer 中的连接计数器的值增加。
  3. 调用 WebConnection.Accepted
    1. 启动“关闭计时器”。一个连接仅持续打开 30 秒。
  4. WebConnection.ReceivedText 。连接正在接收这个请求
    1. 当还在处理请求报头时,把数据分割为行。
    2. 处理请求报头
      1. 处理请求 URL 中提供的请求变量
      2. 如果是 GET 请求:
        1. 创建 WebRequestWebResponse 实例。
        2. 查找相关的网络应用程序。
        3. 如果没有找到 webapplication(网络应用程序),则使用到默认应用程序的 HTTP 重定向(如果设置了)来进行反应。
      3. 如果是 POST 请求:
        1. 创建 WebRequestWebResponse 实例。
        2. 查找相关联的网络应用程序。
      4. 处理报头,通过 WebRequest.ProcessHeaderString 来完成。
        1. 如果是 Authorization: Basic 的情况,则解码用于验证的用户名和密码。
        2. 如果是 = Content-Length = ,则设置 ContentType 变量。
        3. 如果是 Content-Length ,则设置 ContentLength 变量。
    3. 检查请求:
      1. 如果没有创建 WebResponse ,则使用“HTTP 400 错误”做出响应。
      2. 如果没有找到网络应用程序,则使用“HTTP 400 错误”做出响应。
    4. 如果 WebRequest.ContentLength 的值大于 0 并且它是一个 POST 请求,则读取额外的数据。
    5. †调用 WebApplication.PreQuery 。如果结果为 true:
      1. 1. †调用 WebApplication.Query
      2. †调用 WebApplication.PostQuery
    6. 开始清除:
      1. 复原所有变量。
      2. 关闭连接。

†这是您将要创建的部分。

创建网络应用程序


要扩展这个网络服务器的功能,您通常需要创建一个网络应用程序。您可以通过创建 WebApplication 的子类来完成,并且您至少要实现 WebApplication.Query 方法。

IpDrv 中,您会找到一个称为 HelloWeb 的实现示例。

当您的网络应用程序注册后,网络服务器将仅使用它。要注册一个网络应用程序,您需要更新网络服务器配置。编辑 ??Web.ini 文件并更新 [IpDrv.WebServer] 项:

Applications[x]=MyPackage.MyWebApplication
ApplicationPaths[x]=/myweb
这里的 x 是一个空的数组元素。您最多可以由 10 个网络应用程序。可以通过 http://ip:port/myweb 来获得您的网络应用程序。

当网络服务器启动后,它会创建并初始化所有网络应用程序。对于这个网络应用程序来说, path 变量将会被设置为 ApplicationPaths 的值。实现 init() 函数来执行您的网络应用程序的一些初始化操作。当网络服务器关闭时,它将会调用 CleanupApp() 函数。在那个函数中,您应该使得您创建的所有 actor 引用都无效(也就是设置变量为 none 。).

正如在请求过程中所显示的,这个网络应用程序的第一个函数是 PreQuery(..) 。如果这个函数返回为真(默认的行为),那么随后它将会调用 Query(..)PostQuery(..) 函数。这三个函数都接收同样的 2 个参数: WebRequestWebResponse 实例。正如类的名称所预示的, WebRequest 实例包含了关于用户的 HTTP 请求的信息。而 WebResponse 实例可以用于产生对请求的响应。 WebRequest 实例的 URI 变量将会包含产生的相对的 URL。网络应用程序路径已经从原始的 URI 中剥离出来。

处理请求

客户端的请求存储在传入到您的网络应用程序的 Query 函数中。

或许在 WebRequest 中重要的发送变量是 URI 变量。它将包含网络应用程序字段中包含该请求页面。比如,如果客户端产生了请求http://ip:port/myweb/some/page?foo=bar,那么 URI 变量的值是 /some/page 。已经删除了网络应用程序的前缀。并且会将请求变量存储到其他地方。

为了获得 GET 或 POST 请求的变量,您需要使用 GetVariableGetVariableCountGetVariableNumberGetVariables 函数。 GetVariable 函数允许您获得给定请求的第一个值。在先前的发送实例 GetVariable("foo") 中将会返回 bar 。在某些情况下,您会有一些具有同样名称的多个请求变量,比如: http://ip:port/myweb/some/page?foo=bar&quux。在这种情况下,您可以使用 GetVariableCount("foo") 来获得那个变量的数值,并使用 GetVariableNumber("foo", X) 来获得每个值。

您也可以通过 GetHeaderGetHeaders 函数读取请求的报头。HTTP 报头 Content-TypeContent-LengthAuthentication 是在特殊的变量中进行处理并存储的。 Content-TypeContent-Length 仅在 POST 请求中使用。仅会为基础的验证请求处理 Authentication 请求报头。在这种情况下, WebRequest 对象中的 username(用户名)password(密码) 将会包含解码值。

以下实例显示了处理请求的一般方法:

function Query(WebRequest Request, WebResponse Response)
{
    // Each "page" is handled by a separate function(分辨使用函数来处理每个“页面”)
    switch (request.URI)
    {
        case "/page1"
            doPage1(request, response);
            break;
        case "/page2"
            doPage2(request, response);
            break;
        // 等等
    }
}

function doPage1(WebRequest Request, WebResponse Response)
{
    if (request.getVariable("action") ~= "save")
    {
        // save incomming settings(保存输入的设置)
    }
    // produce a response(产生一个响应)
}

产生一个响应

当您的网络应用程序没有提供响应时,网络服务器不会提供任何默认响应。只有在一些非常特殊的情况下,它才会为客户端生成一些有用的信息。所以产生内容是您的网络服务器的责任。

WebResponse 对象用于对客户端产生响应。生成一个响应的最基本的方法是通过使用 SendText 方法来返回内容。但是一般您会想执行的更多一些或者使用或多或少的静态内容,而不是通过虚幻脚本持续地生成响应。

通过 WebResponse 对象生成响应的基本流程是:

  1. 定义内容: AddHeader, Subst, ClearSubst, LoadParsedUHTM, headers, CharSet
  2. HTTPResponse
  3. SendStandardHeaders
  4. 发送内容: IncludeUHTM, SendText, IncludeBinaryFile

前三步完全是可选的步骤。

WebResponse 生成几个标准的 HTTP 报头,在自定义报头之前将会发送这些标准报头。它们是:

$ Server(服务器): "UnrealEngine IpDrv Web Server Build ..." $ Content-Type(内容类型): SendStandardHeaders 函数中提供了 ContentType 变量的值 $ Cache-Control(缓存控制): "max-age=...",网络服务器中的 ExpirationSeconds 的值 $ Expires(过期时间): "...", 网络服务器中的 ExpirationSeconds 的值 $ Connection(连接): “Close(关闭)”。网络服务器一次仅处理一个请求。

有三种常见的创建响应数据的方法:

  1. 手动文本发送
  2. 按原样发送文件
  3. 处理后的 UHTM 文件

发送手动创建的文本

通过使用 SendText 函数,您可以设置发送手动地创建的文档来对网络浏览器做出响应。请参照 HelloWeb 类来获得网络应用程序使用这个方法的示例。

以不做任何修改的方式发送文件

WebResponse 对象提供了 IncludeBinaryFile 函数,这个函数允许您把文件按照它在磁盘上的存储的方式将其发送到客户端。这个方法一般用于发送像图片这样的静态文件,请参照 ImageServer 类。

您可以包含的文件必须位于 UDK/Web 目录中。

注意: 这个 IncludeBinaryFile 不能确保发送响应报头。所以您需要在调用 IncludeBinaryFile 之前调用 SendStandardHeaders 函数。

处理后的 UHTM 文件

UHTM 是一个模板系统,它处理文本文件并替换某些变量及指令。这些文件不是必须是 HTML 文件,也可以使用其它任何文本文件。

有两种特殊的结构。第一种是有一些会被取代的变量。您可以通过以下结构来创建一个替换变量 (substituted variable): <%var_name%> ,这里的 var_name 是变量的名称。您可以通过使用 Subst 函数为这个变量设置值。需要注意的是 SGML 中的变量都不可以被替换。所以它仍然是<!-- <%var_name%> -->

第二个结构是<!-- #include file="file.inc" -->。这将会在当前文件中的此位置包含文件 file.inc 。也会对被包含文件的额外变量和包含指令进行处理。

LoadParsedUHTMIncludeUHTM 函数将会处理该文件。_LoadParsedUHTM_ 函数会将处理后的文件作为字符串返回,而 IncludeUHTM 会将这个处理后的文件发送到网络浏览器上。一般,您使用 LoadParsedUHTM 来为新的替换变量创建一个值。

API


WebApplication

Fields(字段)

Path(路径)

这个域将被设置为网络应用程序的配置的基本路径。请使用这个字段来创建适当的链接。

函数

Init
function Init()

只要创建 WebApplication(网络应用程序)实例后便会调用这个函数。使用这个函数来执行某些重要的初始化操作。建议您不要在这个方法中执行太多的动作。最好把完全的初始化延迟到这个网络应用程序的第一个请求为止。

CleanupApp
function CleanupApp()

在网络服务器被销毁前调用。在这个方法中将您的网络应用程序中到所有 actor 的引用都设置为 none ,从而可以防止内存泄露。

PreQuery
function bool PreQuery(WebRequest Request, WebResponse Response)

调用这个函数来检查网络应用程序是否想要处理给定的查询。如果返回假,则不会调用 QueryPostQuery 方法。

查询
function Query(WebRequest Request, WebResponse Response)

PreQuery 函数返回真后调用这个函数。

PostQuery
function PostQuery(WebRequest Request, WebResponse Response)

Query 函数返回后调用这个函数。

WebRequest

Fields(字段)

RemoteAddr

产生这个请求的客户端的地址。

URI

请求 URL。在通过网络应用程序进行处理的时候,会将该字段从网络应用程序前缀中剥离出来。

Username

当请求中包含了基本的 HTTP Authentication 报头时解码用户名。请参照 RFC 2617 来获得关于这项的更多信息。

Password

当请求中包含了节本的 HTTP Authentication 报头时解码密码。

ContentLength

POST 请求中的字节数。

ContentType

PSOT 数据中的内容类型。

RequestType

将会根据请求种类将其发送到 Request_GETRequest_POST

函数

DecodeBase64
native final function string DecodeBase64(string Encoded)

解码 base64 编码的字符串。

EncodeBase64
native final function string EncodeBase64(string Decoded)

将字符串编码为 base64 格式。

AddHeader
native final function AddHeader(string HeaderName, coerce string Value)

向数据结构中添加一个请求报头。这个函数在请求处理的过程中使用。您不能从网络应用程序中调用这个函数。

GetHeader
native final function string GetHeader(string HeaderName, optional string DefaultValue)

获得给定请求报头的值。如果请求中不存在报头,那么将返回默认值。注意,如果有多个具有同样名称的请求报头,那么仅返回最后一个接收到的报头。报头名称是区分大小写的。

GetHeaders
native final function GetHeaders(out array headers)

获得所有接收到的报头的名称。

AddVariable
native final function AddVariable(string VariableName, coerce string Value)

注册一个接收到的请求变量。这个函数在请求处理的过程中用于在内部使用。不能从网络应用程序中使用这个函数。

GetVariable
native final function string GetVariable(string VariableName, optional string DefaultValue)

获得一个请求变量的值。如果请求变量不存在,则返回默认值。变量的名称是区分大小写的。如果接收到了具有同样名称的多个变量,那么仅返回一个值。请使用 GetVariableNumberGetVariableCount 来分别获得每个值。

GetVariableCount
native final function int GetVariableCount(string VariableName)

返回给定请求变量的变量数量。如果值大于 1,您应该使用 GetVariableNumber 来获取每个值。

GetVariableNumber
native final function string GetVariableNumber(string VariableName, int Number, optional string DefaultValue)

获得给定的请求变量值。如果变量不存在或者没有那个数量个变量,那么将返回默认值。

GetVariables
native final function GetVariables(out array varNames)

获得接收的请求变量的名称。

WebResponse

Fields(字段)

报头

这个数组中包含了将要发送到远程主机的所有报头。它包含了要发送的报头。您可以修改这个数组目录或者通过使用 AddHeader 函数。当内容已经发出后,对于这个字段的修改将不会产生效果。

IncludePath

这是网络服务器可以发送或处理的文件放置的基本目录的相对路径。

连接

它是 WebConnection 实例,用于通过这个实例来发送响应。您不应该使用这个变量来写数据。

函数

FileExists
native final function bool FileExists(string Filename)

当给定的文件名存在于网站的包含目录时返回真。这可以在像 ImageServer 类的静态服务器上使用,来决定给定文件是否存在,如果不存在, WebApplication 可以返回 HTTP 404 Not Found 错误。

Subst
native final function Subst(string Variable, coerce string Value, optional bool bClear)

修改在 IncludeUHTMLoadParsedUHTM 函数中使用的替换变量。第三个可选的参数允许您删除一个先前声明的变量。

ClearSubst
native final function ClearSubst()

删除所有的注册的替换变量。

IncludeUHTM
native final function bool   IncludeUHTM(string Filename)

加载一个 UHTM 文件并处理它。处理结果将直接被发送到远程主机。当文件被正确地包含及处理时这个函数返回为真。提供的文件名称必须存在于子树中,正如在 IncludePath 字段中所声明的。

IncludeBinaryFile
native final function bool   IncludeBinaryFile(string Filename)

以不做任何修改的方式将文件发送到远程客户端。注意,和 IncludeUHTM 不同,这个函数不能确保已经发送了响应报头。因此,在调用这个方法之前,请确保已经发送了报头。

LoadParsedUHTM
native final function string LoadParsedUHTM(string Filename)

IncludeUHTM 函数类似,一个主要的不同之处是它返回处理后的文件作为结果,并且不会把它发送到远程客户端。您可以使用这个函数来创建更多复杂的 UHTM 模板。

GetHTTPExpiration
native final function string GetHTTPExpiration(optional int OffsetSeconds)

创建一个 现在时间+ OffsetSeconds 的 RFC 1123 格式的日期时间。这个事件用于构成 Expires 的响应报头。

SendText
event SendText(string Text, optional bool bNoCRLF)

发送一串文本数据到远程主机。如果 bNoCRLF 是真,那么将不会添加 DOS 行结束符 (0x13 0x10)。这个函数可以确保在发送文本数据之前发送报头。

SendBinary
event SendBinary(int Count, byte B[255])

发送二进制数据到远程主机。这个函数不能确保发送报头。

HTTPResponse
function HTTPResponse(string Header)

发送 HTTP 响应代码。默认情况下,将会使用这个函数发送一个响应 200 OK,这样您就可以发送一个其他的响应。请参照 HTTP RFC 获得关于 HTTP 响应代码的更多细节。HTTP 响应应该在报头参数中给出。例如:

HTTPResponse("HTTP/1.0 404 Not Found");

HTTPHeader
function HTTPHeader(string Header)

发送响应报头。这将可以保证在发送报头之前已经发送了 HTTP 响应代码。您不应该调用这个方法来发送报头。最好通过 AddHeader 函数或直接修改 Headers 域来排队报头。

AddHeader
function AddHeader(string header, optional bool bReplace=true)

将一个报头 添加/更新 到报头列表中。将会最先在可能的情况下发送这个报头。如果想完全地删除特定的报头,可以简单地是它的值为空即可,比如 "X-Header:"。

要想添加具有同样名称的多个报头(设置缓存的报头时需要这种情况),您需要直接地编辑报头数组。

SendHeaders
function SendHeaders()

发送排队的报头。这个函数是通过 SendStandardHeaders 在内部调用的。您不应该使用这个函数。

HTTPError
function HTTPError(int ErrorNum, optional string Data)

这是一个用于发送常见的 HTTP 相应代码的快速方法。比如 400 Bad Request, 401 Unauthorized, 404 Not Found 这样的 HTTP 响应代码。

它将会包含一个具有错误信息的内联的 HTML 响应。您或许想使用更加友好的用户响应来处理这些响应。这是一个便捷的方法。

SendStandardHeaders
function SendStandardHeaders( optional string ContentType, optional bool bCache )

发送标准的报头及所有自定义的报头。当调用这个函数后,您可以安全地包含响应数据。

ContentType 变量用于设置 "Content-Type" 响应报头。它默认是 "text/html"。

如果 bCache 为真,那么它也会包含具有缓存指令的一些报头。这时,它使用了 WebServer.ExpirationSeconds 的值。

这里仅实现了 "Connection: Close" 报头。仅当没有设置报头时才使用其它的默认报头。

重定向
function Redirect(string URL)

发送一个针对重定向客户端到一个不同的 URL 响应 302 Document Moved HTTP 的便捷方法。

SentText
function bool SentText()

如果已经发送了响应数据则返回为真。这时,您不能再发送报头。

SentResponse
function bool SentResponse()

当已经发送了 HTTP 响应代码时返回为真。当执行完这个函数后,您不能改变响应代码。但您仍然可以发送报头。

WebServer(网络服务器)

这可类不能被继承,它仅描述了一些重要的元素。

Fields(字段)

ServerName

这个可选的配置域用于为网络服务器分配主机名。这不会影响主机的行为。它将会使用这个名称来更新 ServerURL 字段,而不是使用本地 IP。

应用程序

加载的网络应用程序的完全符合要求的类名称。这个变量和 ApplicationPaths 字段的关联是十分密切的。您最多可以定义 10 个网络应用程序。

ApplicationPaths

与该网络应用程序相关联的路径。路径的顺序是很重要的,第一个匹配的路径具有优先权。

bEnabled

这个可配置的域可以使您轻而易举地启用或禁用网络服务器。

ListenPort

定义了网络服务器的监听端口。网络服务器仅接受绑定到这个端口上。

MaxConnections

网络服务器支持的可以同时连接到它的最大连接数量。这个值不应该太高,因为它会影响游戏的性能。

DefaultApplication

要使用的默认网络应用程序。这是 Applications 字段中的一个索引。当不能为请求 URL 找到网络应用程序时,那么用户会被重定向到这个网络应用程序。=WebConnection= 使用这个字段。

ExpirationSeconds

一个可配置的域,用于提供定义过期时间的通用位置。WebReponse 类使用它类为可能被缓存的响应设定过期时间。

ServerURL

这个域是在网络服务器启动的过程中产生的。它包含了网络服务器的基础 url。

函数

GetApplication
function WebApplication GetApplication(string URI, out string SubURI)

这个函数返回了给定的 URI 的网络应用程序。这个方法的第二个参数是没有网络应用程序路径的前缀的 URI。

WebConnection

这可类不能被继承,它仅描述了一些重要的元素。

Fields(字段)

MaxValueLength

这个可配置项定义了允许一个请求变量具有的最大长度。它会把传入的值删减为这个长度。为了处理请求,将这个值设置的足够大是很重要的。这个值供 WebRequest 类使用。

MaxLineLength

请求的单独一行的最大长度。在 GET 请求中,这个值限制了变量的长度('?' 后面的东西)。但是在 POST 数据中,它也限制了单独一行的长度。