BestHttp 说明文档翻译

这个当时再找关于网络的插件,就看到了这个,边看文档便翻译,虽然最后还是没有用过这个插件,但这里备份下,说不定下次就用上了。

 

BestHttp 文档

介绍

BestHTTP是一个机遇RFC_2616的HTTP/1.1实现,这个支持几乎所有的unity移动端和pc平台。

我的目标是创建一个简单的使用方法,但是也很有用的插件,作为unity插件能够发挥HTTP/1.1的潜力。

这个文档是个简单快速的教学文档,并没有包含所有的函数与属性。

你也可以在包中找到一些 有用的demo:

* Load Image Test:

一个简单的交互式demo,用来演示下载一张图片并用它来作为texture

* Rest API Test:

这个例子演示怎么使用BestHTTP与RestAPI service结合。这个例子用到了json,但BestHTTP本身是不需要任何第三方依赖的。

* Audio Streaming Test:

一个非常简单的例子来演示BestHTTP的流能力

* Stream Leaderboard Test:

另一个流的例子用来演示 慢的带宽(或较慢的server处理)与有效的客户端的缓存。这种方法我们限制用户与server带宽以及server的处理能力。

安装

你需要将plugins文件夹从BestHttp文件夹中移动到assets文件夹。

快速开始:

首先,你需要添加以下代码:

using BestHTTP;

GET requests

向web Server发送一个请求的简单办法就是创建一个 HTTPRequest对象,并向他的构造函数提供url与回调函数。

创建之后,我们质素要调用Send()函数,就发送请求了:

HTTPRequest request = new HTTPRequest(new Uri(“https://google.com”), onRequestFinished);
request.Send();

其中的回调函数 OnRequestFinished()可能的实现为:

void OnRequestFinished(HTTPRequest request, HTTPResponse response)

{

Debug.Log(“Request Finished! Text received: ” + response.DataAsText);

}

就如你看到的,回调函数参数包含一个源request,以及一个从Server获取到的应答数据的HTTPResponse 对象。

如果这个对象为null表示有错误,并且request对象会有一个异常的属性,可以获取额外的关于这个错误的信息。

当请求是在单独的线程中执行,回调函数都是在Unity的主线程调用的,所以我们不需要做线程同步的一些事情。

如果我们想要写更简洁的代码,可以使用lambda语法,在这个例子中,我们可以这么写:

new HTTPRequest(new Uri(“https://google.com”), (request, response) =>
Debug.Log(“Finished!”)).Send();

POST Requests

上面这个例子是GET requsts. 如果我们不需要指定方法,所有的请求都默认是GET Requests。构造函数还有一个参数用来指定请求的方法:

HTTPRequest request = new HTTPRequest(new Uri(“yourserver.com/posturi”),

HTTPMethods.Post,

OnRequestFinished);

request.AddField(“FieldName”, “Field Value”);

request.Send() ;

你可以使用RawData属性来设置字段来POST:

HTTPRequest request = new HTTPRequest(new Uri(“yourserver.com/posturi”),

HTTPMethods.Post,

OnRequestFinished);

request.RawData = Encoding.UTF8.GetBytes(“Field Value”);

request.Send() ;

除了GET,POST之外,你还可以使用HEAD,PUT,DELETE,PATCH:

HEAD:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”), HTTPMethods.Head,

OnRequestFinished);

request.Send();

PUT:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”), HTTPMethods.Put,

OnRequestFinished);

request.Send();

DELETE:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”),

HTTPMethods.Delete,

OnRequestFinished);

request.Send() ;

PATCH:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”),

HTTPMethods.Patch,

OnRequestFinished);

request.Send();

怎么使用下载数据

大多数时候我们的请求是从server上获取数据。原始的数据可以从HTTPResponse对象的数据属性中访问到。来看个下载image的例子:

new HTTPRequest(new Uri(“http://yourserver.com/path/to/image.png”), (request, response) =>
{
var tex = new Texture2D(0, 0);
tex.LoadImage(response.Data);
guiTexture.texture = tex;
}).Send();

当然有更简单的写作方法:

new HTTPRequest(new Uri(“http://yourserver.com/path/to/image.png”), (request, response) =>
guiTexture.texture = response.DataAsTexture2D).Send();

除了DataAsTexture2D之外还有DataAsText用来转换应答数据为utf8的字符串。在未来可能会有更多的转换类型。

注意:所有的在本文档中的例子没有做错误检测!在你的产品中别忘了做null检测。

从WWW切换

你可以yield一个HTTPRequest通过协同调用:

HTTPRequest request = new HTTPRequest(new Uri(“http :// server.com”));

request.Send();

yield return StartCoroutine (request);

Debug.Log(“Request finished! Downloaded Data:” + request.Response.DataAsText);

Debug.Log的调用只有当request完成之后。这种方式你就可以不必提供一个回调函数了(如果你想你仍然可以使用)。

进阶话题:

这一part将会介绍一些非常有用的用法。

我们可以非常方便的使用HTTPRequest的构造函数来启用或禁用一些基本特性,这些参数如下:

* methodType:

我们想server发送的请求类型,默认的方法类型为 HTTPMethods.Get

* isKeepAlive:

表明我们需要tcp链接,保持与Server的链接,所以连贯的http请求不需要重复链接。默认为true,它可以为我们保留一段时间。否则如果我们知道不再需要requests了,那就可以设置为false.

* disableCache:

告诉BestHTTP使用还是跳过整个缓存机制。如果这个值为true,则系统不会从一个保存的response中查找,也不会保存response.默认是false

身份验证

Best HTTP支持基本的和精华的验证,通过HTTPRequest的Credentials属性:

using BestHTTP.Authentication;

var request = new HTTPRequest(new Uri(“https :// httpbin . org / digest – auth / auth – int / usr / paswd”), (req, resp)

=>

{

if (resp.StatusCode != 401)

Debug.Log(“Authenticated”);

else

Debug.Log(“NOT Authenticated”);

Debug.Log(resp.DataAsText);

5

});

request.Credentials = new Credentials(“usr”, “paswd”);

request.Send()

默认情况下,我们提供给HTTPRequest构造函数的回调函数只会调用一次,当server的应答全部下载完成与处理完成的时候。如果用这种方式,我们下载一个很大的文件超出了我们移动设备的内存,则应用就会crash,用户就会开始骂娘。

要避免这种情况,BestHTTP被设计为很简单的控制这种情况:只要设置某个flag为true, 每获取我们规定大小的数据一次就调用一次我们的回调函数。

另外如果我们没有关闭缓存系统,下载的response就会被保存,所以下一次我们可以从本地缓存stream整个response,而不需要修改我们的代码,甚至不需要去接触web Server(注意:server必须发送有效的缓存头(“Expires”header:查看 RFC))。

看个例子:

   1: var request = new HTTPRequest(new Uri("http://yourserver.com/bigfile"), (req, resp) =>

   2: {

   3:     List<byte[]> fragments = resp.GetStreamedFragments();

   4:     // Write out the downloaded data to a file:

   5:     using (FileStream fs = new FileStream("pathToSave", FileMode.Append))

   6:     foreach(byte[] data in fragments)

   7:     fs.Write(data, 0, data.Length);

   8:     if (resp.IsStreamingFinished)

   9:     Debug.Log(“Download finished!”);

  10: });

  11: request.UseStreaming = true;

  12: request.StreamFragmentSize = 1 * 1024 * 1024; // 1 megabyte

  13: request.DisableCache = true; // already saving to a file, so turn off caching

  14: request.Send();

上面这个代码发生了什么:

* 我们打开了flag – UseStreaming, 所以我们的回调函数可能会被调用多次。

* StreamFragmentSize表明我们每次希望接收到的数据的最大长度。

* 当每StreamFragmentSize的chunk下载之后都被调用一次回调函数,直到IsStreamingFinished为true

* 要获取下载的数据,需要使用 GetStreamedFragments()函数。我们需要将他的结果保存到一个临时变量,因为其内部的buffer将会在这次调用之后清空,所以连续调用这个函数的话只会获得null的结果。

* 我们这里禁止了使用缓存,因为我们已经将他保存到文件中并且不想占用太多的空间。

Caching(缓存)

缓存也是基于HTTP/1.1 RFC. 它使用headers来保存与验证response.缓存机制工作于后台,对于它我们仅有的控制权就是来决定启用还是禁用。

如果被缓存的response有“Expires”的header并包含一个未来的日期,BestHTTP就会直接使用缓存的数据,而不需要在经过server的验证。这意味着我们不需要与server进行tcp链接。这可以保存我们的时间,节约带宽,并离线作业。

虽然缓存是自动的,我们还有一些控制的东西,或者我们可以获取一些信息,通过使用HTTPCacheServices类:

* BeginClear():

在一个单独的线程中,开始时清空整个缓存。

* BeginMaitainence():

通过这个函数,我们可以基于最后访问时间进行对缓存的删除。它删除访问时间对于指定的时间较旧的,我们也可以使用这个函数来保证缓存大小在控制之下:

// Delete cache entries that weren’t accessed in the last two weeks, then delete entries to keep the size of

// the cache under 50 megabytes, starting with the oldest.

// 删除缓存中在两周内没有访问的数据,保持缓存大小在50M以下,从最旧的开始

   1: HTTPCacheService.BeginMaintainence(new HTTPCacheMaintananceParams(TimeSpan.FromDays(14),50 * 1024 * 1024));

* GetCacheSize():

获取缓存的大小,基于bytes

* GetCacheEntryCount():

获取缓存中保存的条目数量。缓存条目的平均大小可以通过计算获得:

   1: float avgSize = GetCacheSize() / (float)GetCacheEntryCount() .

Cookies

控制cookies的操作对于程序员来说是透明的。设置请求cookei头,解析,维护response的Set-Cookie头都在插件中自动完成。

任然有一些控制的途径:

* 可以在每个request中禁用,或者设置全局属性,在HTTPRequest对象的IsCookiesEnabled属性或HTTPManager.IsCookiesEnables属性

* Cookie可以通过调用CookieJar.Clear()函数来删除

* 新的Server发送的cookie,可以通过response的Cookies属性来访问

* 有许多全局设置关于cookies的,可以查看 全局设置 的了解更多。

Proxy(代理)

一个HTTPProxy对象可以设置为一个HTTPRequest的Proxy属性。这种方式将request通过给与的代理:

   1: request.Proxy = new HTTPProxy(new Uri("http :// localhost :3128"));

下载进度跟踪

要跟踪与显示下载进度,你可以使用HTTPRequest类的OnProgress事件。这个事件的参数是源HTTPRequest对象,下载的bytes长度,数据的总长度

   1: var request = new HTTPRequest(new Uri(address), OnFinished);

   2: request.OnProgress = OnDownloadProgress;

   3: request.Send();

   4: void OnDownloadProgress(HTTPRequest request, int downloaded, int length) {

   5: float progressPercent = (downloaded / (length * 100.0f));

   6: Debug.Log(“Downloaded: ” + progressPercent.ToString(“F2”) + “%”);

   7: }

终止一个Request

你可以通过调用HTTPRequest对象的Abort()函数来终止一个进行中的request:

request = new HTTPRequest(new Uri(“http://yourserver.com/bigfile“), (req, resp) => { … });
request.Send();
// And after some time:
request.Abort();

这时回调函数会被调用,response会是null.

超时

对于一个request你可以设置两个超时:

* ConnectTimeout: 通过属性你可以控制你的APP与Server之间要等待一个连接的时间。默认为20秒

   1: request = new HTTPRequest(new Uri("http://yourserver.com/"), (req, resp) => { … });

   2: request.ConnectTimeout = TimeSpan.FromSeconds(2);

   3: request.Send();

* Timeout: 这个属性可以等待一个request的处理时间(发送一个request,下载一个response的时间)

   1: request = new HTTPRequest(new Uri("http://yourserver.com/"), (req, resp) => { … });

   2: request.Timeout = TimeSpan.FromSeconds(10);

   3: request.Send();

全局设置

通过下面这些属性,我们可以改变默认值,否则就在HTTPRequest的构造函数中指定。所以大部分这些属性都是节约时间的快捷方式。

这些改变将会影响到接下来的所有request的创建。

可以通过HTTPManager类的静态属性来改变默认值:

* MaxConnectionPerServer:

允许连接到一个主机的数量。

http://example.orghttps://example.org 是两个不同的server。默认值是4

* KeepAliveDefaultValue:

这个值是HTTPRequest.IsKeepAlive的默认值。如果为false,则tcp链接就会在每次request之前i建立,并在之后关闭。如果希望有连续不断的请求最好改为false(应该为true吧?我看错了?)。HTTPRequest构造函数中的值只对这个request管用。默认值为true

* IsCachingDisabled:

这个属性用来启用或禁用缓存服务。HTTPRequest的构造函数中的这个值只对这个request有效。默认值为true

* MaxConnectionIdleTime:

指定BestHTTP的闲置等待时间在结束最后的request销毁链接之前。默认为2分钟

* IsCookiesEnabled:

这个变量可以启用或禁用Cookie操作。默认为true

* CookieJarSize:

可以被操作的Cookie的数量。默认为10485760(10M)

* EnablePrivateBrowsing:

如果这个操作打开则不会再硬盘上写入Cookie.默认为false

* ConnectTimeOut:

HTTPRequest的默认ConnectTimeout值。默认20秒

* RequestTimeOut:

HTTPRequest的默认Timeout值,默认60秒

示例代码:

   1: HTTPManager.MaxConnectionPerServer = 10;

   2: HTTPManager.RequestTimeout = TimeSpan.FromSeconds(120);

线程安全

因为插件内部是使用线程来平行的处理所有request,所有共享数据(cache,cookie,等等)都被考虑已经实现了线程安全。一些点最好还是要知道一下:

* Request的回调函数的调用,以及其他所有的回调函数(比如WebSocket的回调)都被设计在Unity的主线程(就像unity的事件,比如awake,start,update等等)中调用,所以你不需要做任何线程同步的工作。

创建,发送请求使用多个线程是安全的,但是你需要调用 BestHTTP.HTTPManager.Setup();函数在发送任何请求之前在Unity事件中(比如awake,start)

WebSocket

我们可以通过WebSocket类来使用WebSocket的特性。只需要给WebSocket构造函数传入Server的URL

   1: var webSocket = new WebSocket(new Uri(“wss://html5labs-interop.cloudapp.net/echo”));

之后我们可以注册我们的事件监听:

* OnOpen event:

当与Server正式建立连接时候会被调用,这个事件之后WebSocket的IsOpen属性变为true,知道我们或server端关闭连接,或者有错误发生。

   1: webSocket.OnOpen += OnWebSocketOpen;

   2: private void OnWebSocketOpen(WebSocket webSocket)

   3: {

   4:     Debug.Log("WebSocket Open!");

   5: }

* OnMessage event:

从Server接收到一段文本消息时触发。

   1: webSocket.OnMessage += OnMessageReceived;

   2: private void OnMessageReceived(WebSocket webSocket, string message)

   3: {

   4:     Debug.Log("Text Message received from server: " + message);

   5: }

* OnBinary event:

从Server接收到一段二进制数据时触发

   1: webSocket.OnBinary += OnBinaryMessageReceived;

   2: private void OnBinaryMessageReceived(WebSocket webSocket, byte[] message)

   3: {

   4:     Debug.Log("Binary Message received from server. Length: " + message.Length);

   5: }

* OnClosed event:

当我们或Server关闭连接,或一个内部错误发生的时候会触发。

当客户端通过Close函数关闭连接时可以提供一个Code和一条message来标明关闭的原因。Server可以处理这个CODE与Message.

   1: webSocket.OnClosed += OnWebSocketClosed;

   2: private void OnWebSocketClosed(WebSocket webSocket, UInt16 code, string message)

   3: {

   4:     Debug.Log(“WebSocket Closed!”);

   5: }

* OnError event:

触发时机为:不能连接到server,有内部错误发生,连接丢失。

第二个参数是Exception对象,可以为null.这种情况可以通过WebSocket的InternalRequest来获得更多信息。

   1: webSocket.OnError += OnError;

   2: private void OnError(WebSocket ws, Exception exception)

   3: {

   4:     string errorMsg = string.Empty;

   5:     if (ws.InternalRequest.Response != null)

   6:     errorMsg = string.Format("Status Code from Server: {0} and Message: {1}",

   7:                             ws.InternalRequest.Response.StatusCode,

   8:                             ws.InternalRequest.Response.Message);

   9:     Debug.Log(“An error occured: " + (ex != null ? ex.Message : "Unknown Error " +errorMsg);

  10: }

* OnIncompleteFrame event:

查看 Advanced Websocket 那节吧。

当我们注册了时间之后我们就可以打开连接:

   1: webSocket.Open();

之后我们就可以获得OnOpen事件,我们就可以给Server发送消息了

   1: // Sending out text messages:

   2: webSocket.Send(“Message to the Server”);

   3: // Sending out binary messages:

   4: byte[] buffer = new byte[length];

   5: //fill up the buffer with data

   6: webSocket.Send(buffer);

所有交互完成之后可以关闭连接:

   1: webSocket.Close();

Advanced WebSocket

* Ping messages:

可以启用一个新的线程发送Ping message到server通过设置StartPingThread属性为true在我们接收到OnOpen事件之前。这种方法会定期的向server发送Ping message.间隔可以通过设置PingFrequency属性设置(默认为1000ms)

* Pong messages:

所有从server接收到的Ping message都会被插件自动转换为一个Pong应答

*Streaming:

长文本或二进制消息将会通过片段化获得。这些片段会默认通过插件自动的装配起来,这种机制可以被重写,如果我们注册了OnIncompleteFrame事件的话。这个事件将会在每次客户端接收到不完全的片段的时候调用,这时这些片段将会被插件忽略,不会去组装它们也不会保存它们。这个时间可以用来完成streaming

当前支持的HTTP/1.1特性:

这些特性大部分都是隐藏的或被自动使用的:

● HTTPS

● Store responses in a cache

● Cache validation through the server

● Stream from cache

● Persistent connections

● gzip, deflate content encoding

● Raw and chunked transfer encoding

● Range requests

● Handle redirects

● POST forms and files

● WWW Authentication

FAQ

Q: 我接收到以下错误信息:Internal Compiler error. See the console log for

more information. output was:

Unhandled Exception: System.Reflection.ReflectionTypeLoadException: The classes in the

module cannot be loaded.

A: 检查 安装 那一节的步骤

Q: What Stripping Level can be used with BestHTTP?

A: All stripping levels supported. However there are some cases where you need a link.xml, for

these cases a link.xml is included. You have to copy/merge this xml.

BestHttp 说明文档翻译》有5个想法

发表评论

邮箱地址不会被公开。 必填项已用*标注

* Copy This Password *

* Type Or Paste Password Here *