chore: 规范 http 请求 headers

oneRain 2019-08-09 12:27:35 +08:00
parent 265a34aa9b
commit f2ec04a331
4 changed files with 91 additions and 100 deletions

View File

@ -25,7 +25,14 @@ namespace LeanCloud.Storage.Internal
}
public Dictionary<string, string> Headers {
get; set;
get {
if (AVUser.CurrentUser != null) {
return new Dictionary<string, string> {
{ "X-LC-Session", AVUser.CurrentUser.SessionToken }
};
}
return null;
}
}
public object Content {

View File

@ -6,6 +6,7 @@ using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using System.Linq;
using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal {
@ -13,9 +14,35 @@ namespace LeanCloud.Storage.Internal {
/// Command Runner.
/// </summary>
public class AVCommandRunner {
public const string APPLICATION_JSON = "application/json";
const string APPLICATION_JSON = "application/json";
const string USE_PRODUCTION = "1";
const string USE_DEVELOPMENT = "0";
private readonly System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();
private readonly System.Net.Http.HttpClient httpClient;
public AVCommandRunner() {
httpClient = new System.Net.Http.HttpClient();
ProductHeaderValue product = new ProductHeaderValue(AVClient.Name, AVClient.Version);
httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(product));
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(APPLICATION_JSON));
var conf = AVClient.CurrentConfiguration;
// App ID
httpClient.DefaultRequestHeaders.Add("X-LC-Id", conf.ApplicationId);
// App Signature
long timestamp = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;
if (!string.IsNullOrEmpty(conf.MasterKey) && AVClient.UseMasterKey) {
string sign = MD5.GetMd5String(timestamp + conf.MasterKey);
httpClient.DefaultRequestHeaders.Add("X-LC-Sign", $"{sign},{timestamp},master");
} else {
string sign = MD5.GetMd5String(timestamp + conf.ApplicationKey);
httpClient.DefaultRequestHeaders.Add("X-LC-Sign", $"{sign},{timestamp}");
}
// TODO Session
// Production
httpClient.DefaultRequestHeaders.Add("X-LC-Prod", AVClient.UseProduction ? USE_PRODUCTION : USE_DEVELOPMENT);
}
/// <summary>
///
@ -30,21 +57,22 @@ namespace LeanCloud.Storage.Internal {
IProgress<AVDownloadProgressEventArgs> downloadProgress = null,
CancellationToken cancellationToken = default) {
string content = JsonConvert.SerializeObject(command.Content);
var request = new HttpRequestMessage {
RequestUri = command.Uri,
Method = command.Method,
Content = new StringContent(JsonConvert.SerializeObject(command.Content))
Content = new StringContent(content)
};
var headers = GetHeadersAsync();
foreach (var header in headers) {
if (!string.IsNullOrEmpty(header.Value)) {
request.Content.Headers.ContentType = new MediaTypeHeaderValue(APPLICATION_JSON);
// 特殊 Headers
if (command.Headers != null) {
foreach (KeyValuePair<string, string> header in command.Headers) {
request.Headers.Add(header.Key, header.Value);
}
}
request.Content.Headers.ContentType = new MediaTypeHeaderValue(APPLICATION_JSON);
PrintRequest(httpClient, request, content);
PrintRequest(command, headers);
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
request.Dispose();
@ -87,38 +115,22 @@ namespace LeanCloud.Storage.Internal {
return new Tuple<HttpStatusCode, T>(responseCode, default);
}
private const string revocableSessionTokenTrueValue = "1";
Dictionary<string, string> GetHeadersAsync() {
var headers = new Dictionary<string, string>();
var installationId = AVPlugins.Instance.InstallationIdController.Get();
headers.Add("X-LC-Installation-Id", installationId);
var conf = AVClient.CurrentConfiguration;
headers.Add("X-LC-Id", conf.ApplicationId);
long timestamp = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;
if (!string.IsNullOrEmpty(conf.MasterKey) && AVClient.UseMasterKey) {
string sign = MD5.GetMd5String(timestamp + conf.MasterKey);
headers.Add("X-LC-Sign", $"{sign},{timestamp},master");
} else {
string sign = MD5.GetMd5String(timestamp + conf.ApplicationKey);
headers.Add("X-LC-Sign", $"{sign},{timestamp}");
}
// TODO 重新设计版本号
headers.Add("X-LC-Client-Version", AVClient.VersionString);
headers.Add("X-LC-App-Build-Version", conf.VersionInfo.BuildVersion);
headers.Add("X-LC-App-Display-Version", conf.VersionInfo.DisplayVersion);
headers.Add("X-LC-OS-Version", conf.VersionInfo.OSVersion);
headers.Add("X-LeanCloud-Revocable-Session", revocableSessionTokenTrueValue);
return headers;
}
static void PrintRequest(AVCommand request, Dictionary<string, string> headers) {
static void PrintRequest(System.Net.Http.HttpClient client, HttpRequestMessage request, string content) {
StringBuilder sb = new StringBuilder();
sb.AppendLine("=== HTTP Request Start ===");
sb.AppendLine($"URL: {request.Uri}");
sb.AppendLine($"URL: {request.RequestUri}");
sb.AppendLine($"Method: {request.Method}");
sb.AppendLine($"Headers: {JsonConvert.SerializeObject(headers)}");
sb.AppendLine($"Content: {JsonConvert.SerializeObject(request.Content)}");
sb.AppendLine($"Headers: ");
foreach (var header in client.DefaultRequestHeaders) {
sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
}
foreach (var header in request.Headers) {
sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
}
foreach (var header in request.Content.Headers) {
sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
}
sb.AppendLine($"Content: {content}");
sb.AppendLine("=== HTTP Request End ===");
AVClient.PrintLog(sb.ToString());
}

View File

@ -29,8 +29,8 @@ namespace LeanCloud.Storage.Internal {
public HttpClient() {
client = new NetHttpClient();
// TODO 设置版本号
client.DefaultRequestHeaders.Add("User-Agent", "LeanCloud-dotNet-SDK/" + "2.0.0");
// 设置版本号
client.DefaultRequestHeaders.Add("User-Agent", $"LeanCloud-csharp-sdk-{AVClient.Version}");
}
public HttpClient(NetHttpClient client) {

View File

@ -11,14 +11,12 @@ using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace LeanCloud
{
namespace LeanCloud {
/// <summary>
/// AVClient contains static functions that handle global
/// configuration for the LeanCloud library.
/// </summary>
public static class AVClient
{
public static class AVClient {
public static readonly string[] DateFormatStrings = {
// Official ISO format
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'",
@ -31,13 +29,11 @@ namespace LeanCloud
/// <summary>
/// Represents the configuration of the LeanCloud SDK.
/// </summary>
public struct Configuration
{
public struct Configuration {
/// <summary>
/// 与 SDK 通讯的云端节点
/// </summary>
public enum AVRegion
{
public enum AVRegion {
/// <summary>
/// 默认值LeanCloud 华北节点,同 Public_North_China
/// </summary>
@ -81,8 +77,7 @@ namespace LeanCloud
/// Any values set here will overwrite those that are automatically configured by
/// any platform-specific migration library your app includes.
/// </summary>
public struct VersionInformation
{
public struct VersionInformation {
/// <summary>
/// The build number of your app.
/// </summary>
@ -110,10 +105,8 @@ namespace LeanCloud
/// </summary>
public AVRegion Region { get; set; }
internal int RegionValue
{
get
{
internal int RegionValue {
get {
return (int)Region;
}
}
@ -178,29 +171,24 @@ namespace LeanCloud
/// </summary>
public static Configuration CurrentConfiguration { get; internal set; }
internal static Version Version
{
get
{
var assemblyName = new AssemblyName(typeof(AVClient).GetTypeInfo().Assembly.FullName);
return assemblyName.Version;
}
}
internal static string APIVersion {
get {
return "1.1";
}
}
public static string Name {
get {
return "LeanCloud-CSharp-SDK";
}
}
/// <summary>
/// 当前 SDK 版本号
/// </summary>
public static string VersionString
{
get
{
return "net-v0.1.0";
public static string Version {
get {
return "0.1.0";
}
}
@ -214,10 +202,8 @@ namespace LeanCloud
/// </param>
/// <param name="applicationKey">The .NET API Key provided in the LeanCloud dashboard.
/// </param>
public static void Initialize(string applicationId, string applicationKey)
{
Initialize(new Configuration
{
public static void Initialize(string applicationId, string applicationKey) {
Initialize(new Configuration {
ApplicationId = applicationId,
ApplicationKey = applicationKey
});
@ -229,16 +215,14 @@ namespace LeanCloud
/// 启动日志打印
/// </summary>
/// <param name="trace"></param>
public static void HttpLog(Action<string> trace)
{
public static void HttpLog(Action<string> trace) {
LogTracker = trace;
}
/// <summary>
/// 打印 HTTP 访问日志
/// </summary>
/// <param name="log"></param>
public static void PrintLog(string log)
{
public static void PrintLog(string log) {
LogTracker?.Invoke(log);
}
@ -262,8 +246,7 @@ namespace LeanCloud
/// </summary>
/// <param name="configuration">The configuration to initialize LeanCloud with.
/// </param>
public static void Initialize(Configuration configuration)
{
public static void Initialize(Configuration configuration) {
Config(configuration);
AVObject.RegisterSubclass<AVUser>();
@ -271,15 +254,11 @@ namespace LeanCloud
AVObject.RegisterSubclass<AVSession>();
}
internal static void Config(Configuration configuration)
{
lock (mutex)
{
internal static void Config(Configuration configuration) {
lock (mutex) {
var nodeHash = configuration.ApplicationId.Split('-');
if (nodeHash.Length > 1)
{
if (nodeHash[1].Trim() == "9Nh9j0Va")
{
if (nodeHash.Length > 1) {
if (nodeHash[1].Trim() == "9Nh9j0Va") {
configuration.Region = Configuration.AVRegion.Public_East_China;
}
}
@ -288,8 +267,7 @@ namespace LeanCloud
}
}
internal static void Clear()
{
internal static void Clear() {
AVPlugins.Instance.AppRouterController.Clear();
AVPlugins.Instance.Reset();
AVUser.ClearInMemoryUser();
@ -299,16 +277,13 @@ namespace LeanCloud
/// Switch app.
/// </summary>
/// <param name="configuration">Configuration.</param>
public static void Switch(Configuration configuration)
{
public static void Switch(Configuration configuration) {
Clear();
Initialize(configuration);
}
public static void Switch(string applicationId, string applicationKey, Configuration.AVRegion region = Configuration.AVRegion.Public_North_China)
{
var configuration = new Configuration
{
public static void Switch(string applicationId, string applicationKey, Configuration.AVRegion region = Configuration.AVRegion.Public_North_China) {
var configuration = new Configuration {
ApplicationId = applicationId,
ApplicationKey = applicationKey,
Region = region
@ -316,8 +291,7 @@ namespace LeanCloud
Switch(configuration);
}
public static string BuildQueryString(IDictionary<string, object> parameters)
{
public static string BuildQueryString(IDictionary<string, object> parameters) {
return string.Join("&", (from pair in parameters
let valueString = pair.Value as string
select string.Format("{0}={1}",
@ -327,11 +301,9 @@ namespace LeanCloud
.ToArray());
}
internal static IDictionary<string, string> DecodeQueryString(string queryString)
{
internal static IDictionary<string, string> DecodeQueryString(string queryString) {
var dict = new Dictionary<string, string>();
foreach (var pair in queryString.Split('&'))
{
foreach (var pair in queryString.Split('&')) {
var parts = pair.Split(new char[] { '=' }, 2);
dict[parts[0]] = parts.Length == 2 ? Uri.UnescapeDataString(parts[1].Replace("+", " ")) : null;
}