You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
9.1 KiB
260 lines
9.1 KiB
using Apewer.Network;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace Apewer.Web
|
|
{
|
|
|
|
/// <summary>请求 API 框架的客户端。</summary>
|
|
public class ApiClient
|
|
{
|
|
|
|
private const int DefaultTimeout = 60000;
|
|
|
|
/// <summary>服务器 URL 根路径。</summary>
|
|
public virtual string UrlRoot { get; set; }
|
|
|
|
/// <summary>使用随机值,并验证响应。</summary>
|
|
public virtual bool UseRandom { get; set; }
|
|
|
|
/// <summary>账号令牌。</summary>
|
|
public virtual string Ticket { get; set; }
|
|
|
|
/// <summary>会话标识。</summary>
|
|
public virtual string Session { get; set; }
|
|
|
|
/// <summary>用户代理。</summary>
|
|
public virtual string UserAgent { get; set; }
|
|
|
|
/// <summary>请求超时,默认值为 60 秒。</summary>
|
|
public virtual int Timeout { get; set; } = DefaultTimeout;
|
|
|
|
void Send(HttpClient client, string random, Action<Json> succeed = null, Action<string> failed = null)
|
|
{
|
|
client.UserAgent = UserAgent;
|
|
var ex = client.Send();
|
|
if (ex != null)
|
|
{
|
|
failed?.Invoke(ex.Message());
|
|
return;
|
|
}
|
|
|
|
if (succeed == null && failed == null) return;
|
|
|
|
var body = client.ResponseData;
|
|
if (body == null || body.LongLength < 1L)
|
|
{
|
|
failed?.Invoke("服务器返回了空数据。");
|
|
return;
|
|
}
|
|
|
|
var json = Json.From(body.Text());
|
|
if (!json)
|
|
{
|
|
failed?.Invoke("服务器返回了非 Json 格式的数据。");
|
|
return;
|
|
}
|
|
|
|
var status = json["status"];
|
|
if (status != "ok")
|
|
{
|
|
var message = json["message"];
|
|
failed?.Invoke(message);
|
|
return;
|
|
}
|
|
|
|
var data = json.GetProperty("data");
|
|
succeed?.Invoke(data);
|
|
}
|
|
|
|
void Send(HttpClient client, string random, Action<byte[]> succeed = null, Action<string> failed = null)
|
|
{
|
|
client.UserAgent = UserAgent;
|
|
var ex = client.Send();
|
|
if (ex != null)
|
|
{
|
|
failed?.Invoke(ex.Message());
|
|
return;
|
|
}
|
|
|
|
if (succeed == null) return;
|
|
|
|
var body = client.ResponseData;
|
|
succeed?.Invoke(body);
|
|
}
|
|
|
|
string Random() => UseRandom ? TextUtility.Random(8) : null;
|
|
|
|
#region get
|
|
|
|
/// <summary>发起 GET 请求,获取响应中的 data 属性。</summary>
|
|
public void Get(string urlPath, Action<Json> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Get(urlPath);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
/// <summary>发起 GET 请求,获取响应的主体。</summary>
|
|
public void Get(string urlPath, Action<byte[]> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Get(urlPath);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
HttpClient Get(string urlPath)
|
|
{
|
|
var random = Random();
|
|
var client = new HttpClient();
|
|
client.Url = MergeUrl(urlPath, random);
|
|
client.Method = HttpMethod.GET;
|
|
client.Timeout = Timeout;
|
|
return client;
|
|
}
|
|
|
|
/// <summary>发起 POST 请求,上传指定数据,获取响应中的 data 属性。</summary>
|
|
public void Upload(string urlPath, byte[] bytes, Action<Json> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Upload(urlPath, random, bytes);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
/// <summary>发起 POST 请求,上传指定数据,获取响应的主体。</summary>
|
|
public void Upload(string urlPath, byte[] bytes, Action<byte[]> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Upload(urlPath, random, bytes);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
HttpClient Upload(string urlPath, string random, byte[] bytes)
|
|
{
|
|
var client = new HttpClient();
|
|
client.Url = MergeUrl(urlPath, random);
|
|
client.Method = HttpMethod.POST;
|
|
client.Timeout = Timeout;
|
|
client.RequestContentType = "appliction/octet-stream";
|
|
client.RequestData = bytes;
|
|
return client;
|
|
}
|
|
|
|
string MergeUrl(string urlPath, string random)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.Append(TextUtility.AssureEnds(UrlRoot, "/", true));
|
|
|
|
var query = null as string;
|
|
if (!string.IsNullOrEmpty(urlPath))
|
|
{
|
|
var offset = urlPath.IndexOf("#");
|
|
if (offset > -1) urlPath = urlPath.Substring(0, offset);
|
|
|
|
offset = urlPath.IndexOf("?");
|
|
if (offset < 0)
|
|
{
|
|
sb.Append(urlPath);
|
|
}
|
|
else
|
|
{
|
|
sb.Append(urlPath.Substring(0, offset));
|
|
query = urlPath.Substring(offset + 1);
|
|
}
|
|
}
|
|
|
|
var session = Session;
|
|
var ticket = Ticket;
|
|
var ps = ApiUtility.Parameters(query, false);
|
|
if (!string.IsNullOrEmpty(random) && !ps.HasKey("random", true)) ps.Add("random", random);
|
|
if (!string.IsNullOrEmpty(session) && !ps.HasKey("session", true)) ps.Add("session", session);
|
|
if (!string.IsNullOrEmpty(ticket) && !ps.HasKey("ticket", true)) ps.Add("ticket", ticket);
|
|
if (ps.Count > 0)
|
|
{
|
|
var first = true;
|
|
foreach (var p in ps)
|
|
{
|
|
if (first)
|
|
{
|
|
sb.Append("?");
|
|
first = false;
|
|
}
|
|
else sb.Append("&");
|
|
sb.Append(p.Key);
|
|
sb.Append("=");
|
|
sb.Append(p.Value);
|
|
}
|
|
}
|
|
var url = sb.ToString();
|
|
return url;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region post
|
|
|
|
/// <summary>发起 POST 请求,获取响应中的 data 属性。</summary>
|
|
public void Post(string urlPath, Json data, Action<Json> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Post(urlPath, random, null, null, data);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
/// <summary>发起 POST 请求,获取响应中的 data 属性。</summary>
|
|
public void Post(string application, string function, Json data, Action<Json> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Post(null, random, application, function, data);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
/// <summary>发起 POST 请求,获取响应的主体。</summary>
|
|
public void Post(string urlPath, Json data, Action<byte[]> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Post(urlPath, random, null, null, data);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
/// <summary>发起 POST 请求,获取响应的主体。</summary>
|
|
public void Post(string application, string function, Json data, Action<byte[]> succeed = null, Action<string> failed = null)
|
|
{
|
|
var random = Random();
|
|
var client = Post(null, random, application, function, data);
|
|
Send(client, random, succeed, failed);
|
|
}
|
|
|
|
HttpClient Post(string urlPath, string random, string application, string function, Json data)
|
|
{
|
|
var json = Json.NewObject();
|
|
if (!string.IsNullOrEmpty(application)) json.SetProperty("application", application);
|
|
if (!string.IsNullOrEmpty(function)) json.SetProperty("function", function);
|
|
if (!string.IsNullOrEmpty(random)) json.SetProperty("random", random);
|
|
|
|
var session = Session;
|
|
if (!string.IsNullOrEmpty(session)) json.SetProperty("session", session);
|
|
|
|
var ticket = Ticket;
|
|
if (!string.IsNullOrEmpty(random)) json.SetProperty("ticket", ticket);
|
|
|
|
if (data != null) json.SetProperty("data", data);
|
|
|
|
var url = TextUtility.AssureEnds(UrlRoot, "/", true);
|
|
if (!string.IsNullOrEmpty(urlPath)) url += urlPath.StartsWith("/") ? urlPath.Substring(1) : urlPath;
|
|
|
|
var client = new HttpClient();
|
|
client.Url = url;
|
|
client.Method = HttpMethod.POST;
|
|
client.Timeout = Timeout;
|
|
client.RequestContentType = "application/json";
|
|
client.RequestData = json.ToString().Bytes();
|
|
return client;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|
|
|