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

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
}
}