修改在linux下路径的bug
This commit is contained in:
@@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileServices", "FileService
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWeb", "TestWeb\TestWeb.csproj", "{B64F2077-52A2-472F-883F-57EBE8805F8D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QiniuFileService", "Qiniu\QiniuFileService.csproj", "{218AEB0B-2C51-42D7-98E0-4C1FE7E09E69}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Qiniu.FileService", "Qiniu\Qiniu.FileService.csproj", "{218AEB0B-2C51-42D7-98E0-4C1FE7E09E69}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -4,6 +4,16 @@
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.0;netstandard2.1;netcoreapp3.0</TargetFrameworks>
|
||||
<RootNamespace>Ufangx.FileServices</RootNamespace>
|
||||
<AssemblyName>FileServices</AssemblyName>
|
||||
<Authors>Jackson.bruce</Authors>
|
||||
<Company>Ufangx</Company>
|
||||
<Description>File management, super large file upload, breakpoint renewal</Description>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://github.com/JacksonBruce/FileServices.git</RepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/JacksonBruce/FileServices</PackageProjectUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>file service web uploader html5 uploader breakpoint renewal</PackageTags>
|
||||
<Copyright>Copyright (c) 2020-$([System.DateTime]::Now.Year) Jackson.Bruce</Copyright>
|
||||
<Version>1.0.0-beta.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)|$(Platform)'=='netstandard2.0|AnyCPU'">
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Ufangx.FileServices.Local
|
||||
}
|
||||
protected string physicalPath(string path) {
|
||||
|
||||
return Path.Combine(option.StorageRootDir, path.Trim().Replace('/', '\\').TrimStart('\\'));
|
||||
return Path.Combine(option.StorageRootDir, path.Trim().Replace('\\', '/').TrimStart('/'));
|
||||
}
|
||||
protected bool CreateDirIfNonexistence(string path) {
|
||||
|
||||
|
||||
@@ -22,14 +22,15 @@ namespace Ufangx.FileServices.Local
|
||||
}
|
||||
string GetTempDir(string path, string key)
|
||||
{
|
||||
return Path.Combine(Path.GetDirectoryName(path), $"_tmp{key}");
|
||||
return Path.Combine(Path.GetDirectoryName(path), $"_tmp{key}").Replace('\\','/');
|
||||
}
|
||||
bool CheckFiles(string dir, long count) {
|
||||
//Console.WriteLine("正在检查文件。。。");
|
||||
//Stopwatch sw = Stopwatch.StartNew();
|
||||
for (long i = 0; i < count; i++)
|
||||
{
|
||||
if (!File.Exists(Path.Combine(dir, $"{i}"))) { return false; }
|
||||
string path = Path.Combine(dir, $"{i}").Replace('\\', '/');
|
||||
if (!File.Exists(path)) { return false; }
|
||||
}
|
||||
//sw.Stop();
|
||||
//Console.WriteLine($"检查{count}个文件,用时:{sw.Elapsed.TotalMilliseconds}毫秒");
|
||||
@@ -52,7 +53,7 @@ namespace Ufangx.FileServices.Local
|
||||
{
|
||||
for (long i = 0; i < count; i++)
|
||||
{
|
||||
var blob = await GetBlob(Path.Combine(dir, $"{i}"), token);
|
||||
var blob = await GetBlob(Path.Combine(dir, $"{i}").Replace('\\','/'), token);
|
||||
await fs.WriteAsync(blob, 0, blob.Length, token);
|
||||
}
|
||||
await fs.FlushAsync(token);
|
||||
@@ -87,7 +88,7 @@ namespace Ufangx.FileServices.Local
|
||||
}
|
||||
var p = physicalPath(info.StoreName);
|
||||
string tempdir = GetTempDir(p,info.Key);
|
||||
var tmp = Path.Combine(tempdir, $"{blob.BlobIndex}");
|
||||
var tmp = Path.Combine(tempdir, $"{blob.BlobIndex}").Replace('\\','/');
|
||||
if (CreateDirIfNonexistence(tmp))
|
||||
{
|
||||
var stream = blob.Data;
|
||||
|
||||
@@ -41,26 +41,26 @@ namespace Ufangx.FileServices.Services
|
||||
nameRule = FileNameRule.Ascending;
|
||||
}
|
||||
if (directory == null) { directory = string.Empty; }
|
||||
directory = Path.Combine(scheme?.StoreDirectory ?? string.Empty, directory);
|
||||
directory = Path.Combine(scheme?.StoreDirectory ?? string.Empty, directory).Replace('\\', '/');
|
||||
string fileName;
|
||||
switch (nameRule)
|
||||
{
|
||||
case FileNameRule.Ascending:
|
||||
fileName = Path.Combine(directory, originName);
|
||||
fileName = Path.Combine(directory, originName).Replace('\\', '/');
|
||||
int index = 0;
|
||||
while (await fileService.Exists(fileName))
|
||||
{
|
||||
fileName = Path.Combine(directory, $"{Path.GetFileNameWithoutExtension(originName)}({++index}){Path.GetExtension(originName)}");
|
||||
fileName = Path.Combine(directory, $"{Path.GetFileNameWithoutExtension(originName)}({++index}){Path.GetExtension(originName)}").Replace('\\', '/');
|
||||
}
|
||||
break;
|
||||
case FileNameRule.Date:
|
||||
fileName = Path.Combine(directory, string.Format(fileNameRuleOptions?.Format ?? "{0:yyyyMMddHHmmss}", DateTime.Now) + Path.GetExtension(originName));
|
||||
fileName = Path.Combine(directory, string.Format(fileNameRuleOptions?.Format ?? "{0:yyyyMMddHHmmss}", DateTime.Now) + Path.GetExtension(originName)).Replace('\\', '/');
|
||||
break;
|
||||
case FileNameRule.Custom:
|
||||
fileName = Path.Combine(directory, fileNameRuleOptions.Custom(originName));
|
||||
fileName = Path.Combine(directory, fileNameRuleOptions.Custom(originName)).Replace('\\', '/');
|
||||
break;
|
||||
default:
|
||||
fileName = Path.Combine(directory, originName);
|
||||
fileName = Path.Combine(directory, originName).Replace('\\', '/');
|
||||
break;
|
||||
}
|
||||
return fileName.Replace('\\', '/');
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Qiniu.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP 内容类型(Content-Type)
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class ContentType
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源类型:普通文本
|
||||
/// </summary>
|
||||
public static readonly string TEXT_PLAIN = "text/plain";
|
||||
|
||||
/// <summary>
|
||||
/// 资源类型:JSON字符串
|
||||
/// </summary>
|
||||
public static readonly string APPLICATION_JSON = "application/json";
|
||||
|
||||
/// <summary>
|
||||
/// 资源类型:未知类型(数据流)
|
||||
/// </summary>
|
||||
public static readonly string APPLICATION_OCTET_STREAM = "application/octet-stream";
|
||||
|
||||
/// <summary>
|
||||
/// 资源类型:表单数据(键值对)
|
||||
/// </summary>
|
||||
public static readonly string WWW_FORM_URLENC = "application/x-www-form-urlencoded";
|
||||
|
||||
/// <summary>
|
||||
/// 资源类型:多分部数据
|
||||
/// </summary>
|
||||
public static readonly string MULTIPART_FORM_DATA = "multipart/form-data";
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Qiniu.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP 状态码
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum HttpCode
|
||||
{
|
||||
#region _PRE_
|
||||
|
||||
/// <summary>
|
||||
/// 成功
|
||||
/// </summary>
|
||||
OK = 200,
|
||||
|
||||
/// <summary>
|
||||
/// 部分OK
|
||||
/// </summary>
|
||||
PARTLY_OK = 298,
|
||||
|
||||
/// <summary>
|
||||
/// 请求错误
|
||||
/// </summary>
|
||||
BAD_REQUEST = 400,
|
||||
|
||||
/// <summary>
|
||||
/// 认证授权失败
|
||||
/// </summary>
|
||||
AUTHENTICATION_FAILED = 401,
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝访问
|
||||
/// </summary>
|
||||
ACCESS_DENIED = 403,
|
||||
|
||||
/// <summary>
|
||||
/// 资源不存在
|
||||
/// </summary>
|
||||
OBJECT_NOT_FOUND = 404,
|
||||
|
||||
/// <summary>
|
||||
/// CRC32校验失败
|
||||
/// </summary>
|
||||
CRC32_CHECK_FAILEd = 406,
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件大小超限
|
||||
/// </summary>
|
||||
FILE_SIZE_EXCEED = 413,
|
||||
|
||||
/// <summary>
|
||||
/// 镜像回源失败
|
||||
/// </summary>
|
||||
PREFETCH_FAILED = 478,
|
||||
|
||||
/// <summary>
|
||||
/// 错误网关
|
||||
/// </summary>
|
||||
BAD_GATEWAY = 502,
|
||||
|
||||
/// <summary>
|
||||
/// 服务端不可用
|
||||
/// </summary>
|
||||
SERVER_UNAVAILABLE = 503,
|
||||
|
||||
/// <summary>
|
||||
/// 服务端操作超时
|
||||
/// </summary>
|
||||
SERVER_TIME_EXCEED = 504,
|
||||
|
||||
/// <summary>
|
||||
/// 单个资源访问频率过高
|
||||
/// </summary>
|
||||
TOO_FREQUENT_ACCESS = 573,
|
||||
|
||||
/// <summary>
|
||||
/// 回调失败
|
||||
/// </summary>
|
||||
CALLBACK_FAILED = 579,
|
||||
|
||||
/// <summary>
|
||||
/// 服务端操作失败
|
||||
/// </summary>
|
||||
SERVER_OPERATION_FAILED = 599,
|
||||
|
||||
/// <summary>
|
||||
/// 资源内容被修改
|
||||
/// </summary>
|
||||
CONTENT_MODIFIED = 608,
|
||||
|
||||
/// <summary>
|
||||
/// 文件不存在
|
||||
/// </summary>
|
||||
FILE_NOT_EXIST = 612,
|
||||
|
||||
/// <summary>
|
||||
/// 文件已存在
|
||||
/// </summary>
|
||||
FILE_EXISTS = 614,
|
||||
|
||||
/// <summary>
|
||||
/// 空间数量已达上限
|
||||
/// </summary>
|
||||
BUCKET_COUNT_LIMIT = 630,
|
||||
|
||||
/// <summary>
|
||||
/// 空间或者文件不存在
|
||||
/// </summary>
|
||||
BUCKET_NOT_EXIST = 631,
|
||||
|
||||
/// <summary>
|
||||
/// 列举资源(list)使用了非法的marker
|
||||
/// </summary>
|
||||
INVALID_MARKER = 640,
|
||||
|
||||
/// <summary>
|
||||
/// 在断点续上传过程中,后续上传接收地址不正确或ctx信息已过期。
|
||||
/// </summary>
|
||||
CONTEXT_EXPIRED = 701,
|
||||
|
||||
#endregion _PRE_
|
||||
|
||||
#region _USR_
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码 (默认值)
|
||||
/// </summary>
|
||||
USER_UNDEF = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码 (用户取消)
|
||||
/// </summary>
|
||||
USER_CANCELED = -2,
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码 (用户暂停)
|
||||
/// </summary>
|
||||
USER_PAUSED = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码 (用户继续)
|
||||
/// </summary>
|
||||
USER_RESUMED = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码 (需要重试)
|
||||
/// </summary>
|
||||
USER_NEED_RETRY = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码 (异常或错误)
|
||||
/// </summary>
|
||||
INVALID_ARGUMENT = -4,
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码(文件不合法)
|
||||
/// </summary>
|
||||
INVALID_FILE = -3,
|
||||
|
||||
/// <summary>
|
||||
/// 自定义HTTP状态码(凭证不合法)
|
||||
/// </summary>
|
||||
INVALID_TOKEN = -5,
|
||||
|
||||
#endregion _USR_
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Qiniu.Util;
|
||||
|
||||
namespace Qiniu.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpManager for .NET 4.5+
|
||||
/// </summary>
|
||||
public class HttpManager : IDisposable
|
||||
{
|
||||
public static readonly HttpManager SharedInstance = new HttpManager();
|
||||
|
||||
private readonly HttpClient _client;
|
||||
private string _userAgent;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="allowAutoRedirect">是否允许HttpWebRequest的“重定向”,默认禁止</param>
|
||||
public HttpManager(bool allowAutoRedirect = false) : this(null, allowAutoRedirect)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="baseUrl">API Host,可选</param>
|
||||
/// <param name="allowAutoRedirect">是否允许HttpWebRequest的“重定向”,默认禁止</param>
|
||||
public HttpManager(string baseUrl, bool allowAutoRedirect = false)
|
||||
{
|
||||
_client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = allowAutoRedirect });
|
||||
if (!string.IsNullOrEmpty(baseUrl)) _client.BaseAddress = new Uri(baseUrl);
|
||||
_client.DefaultRequestHeaders.ExpectContinue = false;
|
||||
SetUserAgent(GetUserAgent());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_client?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 客户端标识(UserAgent),示例:"SepcifiedClient/1.1 (Universal)"
|
||||
/// </summary>
|
||||
/// <returns>客户端标识UA</returns>
|
||||
public static string GetUserAgent()
|
||||
{
|
||||
#if NETSTANDARD1_3
|
||||
var osDesc = $"{System.Runtime.InteropServices.RuntimeInformation.OSDescription}";
|
||||
#else
|
||||
var osDesc = $"{Environment.OSVersion.Platform}; {Environment.OSVersion.Version}";
|
||||
#endif
|
||||
return $"{QiniuCSharpSdk.Alias}/{QiniuCSharpSdk.Version} ({QiniuCSharpSdk.RTFX}; {osDesc})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置自定义的客户端标识(UserAgent),示例:"SepcifiedClient/1.1 (Universal)"
|
||||
/// 如果设置为空白或者不设置,SDK会自动使用默认的UserAgent
|
||||
/// </summary>
|
||||
/// <param name="userAgent">用户自定义的UserAgent</param>
|
||||
/// <returns>客户端标识UA</returns>
|
||||
public void SetUserAgent(string userAgent)
|
||||
{
|
||||
_userAgent = userAgent;
|
||||
_client.DefaultRequestHeaders.UserAgent.Clear();
|
||||
if (!string.IsNullOrEmpty(userAgent))
|
||||
{
|
||||
_client.DefaultRequestHeaders.UserAgent.ParseAdd(userAgent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多部分表单数据(multi-part form-data)的分界(boundary)标识
|
||||
/// </summary>
|
||||
/// <returns>分界(boundary)标识字符串</returns>
|
||||
public static string CreateFormDataBoundary()
|
||||
{
|
||||
var now = DateTime.UtcNow.Ticks.ToString();
|
||||
return $"-------{QiniuCSharpSdk.Alias}Boundary{Hashing.CalcMd5X(now)}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送HTTP请求
|
||||
/// </summary>
|
||||
/// <param name="request">请求消息</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP请求的响应结果</returns>
|
||||
public async Task<HttpResult> SendAsync(HttpRequestMessage request, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var result = new HttpResult();
|
||||
HttpResponseMessage response = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
request.Headers.Add("Authorization", token);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
response = await _client.SendAsync(request);
|
||||
await result.ReadAsync(response, binaryMode);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
var wrapper = new Exception($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.ffff}] [{_userAgent}] [HTTP-{request.Method.Method}] Error: ", exception);
|
||||
await result.ReadErrorAsync(wrapper, response);
|
||||
}
|
||||
finally
|
||||
{
|
||||
response?.Dispose();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-GET方法
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-GET的响应结果</returns>
|
||||
public Task<HttpResult> GetAsync(string url, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
return SendAsync(request, token, binaryMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-POST方法(不包含body数据)
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-POST的响应结果</returns>
|
||||
public Task<HttpResult> PostAsync(string url, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, url);
|
||||
return SendAsync(request, token, binaryMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-POST方法
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="content">主体数据[可选]</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-POST的响应结果</returns>
|
||||
public Task<HttpResult> PostAsync(string url, HttpContent content = null, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, url) { Content = content };
|
||||
return SendAsync(request, token, binaryMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-POST方法(包含body数据)
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="data">主体数据(字节数据)</param>
|
||||
/// <param name="mimeType">主体数据内容类型</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-POST的响应结果</returns>
|
||||
public Task<HttpResult> PostDataAsync(string url, byte[] data, string mimeType = "application/octet-stream", string token = null, bool binaryMode = false)
|
||||
{
|
||||
var content = new ByteArrayContent(data);
|
||||
content.Headers.ContentType = MediaTypeHeaderValue.Parse(mimeType);
|
||||
return PostAsync(url, content, token, binaryMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-POST方法(包含表单数据)
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="data">表单数据</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-POST的响应结果</returns>
|
||||
public Task<HttpResult> PostFormAsync(string url, string data, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var content = new StringContent(data, Encoding.UTF8, ContentType.WWW_FORM_URLENC);
|
||||
return PostAsync(url, content, token, binaryMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-POST方法(包含表单数据)
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="data">表单数据</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-POST的响应结果</returns>
|
||||
public Task<HttpResult> PostFormAsync(string url, byte[] data, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var content = new ByteArrayContent(data);
|
||||
content.Headers.ContentType = MediaTypeHeaderValue.Parse(ContentType.WWW_FORM_URLENC);
|
||||
return PostAsync(url, content, token, binaryMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-POST方法(包含JSON文本的body数据)
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="data">主体数据(JSON文本)</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-POST的响应结果</returns>
|
||||
public Task<HttpResult> PostJsonAsync(string url, string data, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var content = new StringContent(data, Encoding.UTF8, ContentType.APPLICATION_JSON);
|
||||
return PostAsync(url, content, token, binaryMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP-POST方法(包含普通文本的body数据)
|
||||
/// </summary>
|
||||
/// <param name="url">请求目标URL</param>
|
||||
/// <param name="data">主体数据(普通文本)</param>
|
||||
/// <param name="token">令牌(凭证)[可选]</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容(默认:否,即表示以文本方式读取)</param>
|
||||
/// <returns>HTTP-POST的响应结果</returns>
|
||||
public Task<HttpResult> PostTextAsync(string url, string data, string token = null, bool binaryMode = false)
|
||||
{
|
||||
var content = new StringContent(data, Encoding.UTF8, ContentType.TEXT_PLAIN);
|
||||
return PostAsync(url, content, token, binaryMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Qiniu.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP请求(GET,POST等)的返回消息
|
||||
/// </summary>
|
||||
public class HttpResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 非法上传凭证错误
|
||||
/// </summary>
|
||||
public static readonly HttpResult InvalidToken = new HttpResult
|
||||
{
|
||||
Code = (int)HttpCode.INVALID_TOKEN,
|
||||
Text = "invalid uptoken"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 非法文件错误
|
||||
/// </summary>
|
||||
public static readonly HttpResult InvalidFile = new HttpResult
|
||||
{
|
||||
Code = (int)HttpCode.INVALID_FILE,
|
||||
Text = "invalid file"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 初始化(所有成员默认值,需要后续赋值)
|
||||
/// </summary>
|
||||
public HttpResult()
|
||||
{
|
||||
Code = (int)HttpCode.USER_UNDEF;
|
||||
Text = null;
|
||||
Data = null;
|
||||
|
||||
RefCode = (int)HttpCode.USER_UNDEF;
|
||||
RefInfo = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 状态码 (200表示OK)
|
||||
/// </summary>
|
||||
public int Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息或错误文本
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息或错误(二进制格式)
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参考代码(用户自定义)
|
||||
/// </summary>
|
||||
public int RefCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加信息(用户自定义,如Exception内容)
|
||||
/// </summary>
|
||||
public string RefText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参考信息(从返回消息WebResponse的头部获取)
|
||||
/// </summary>
|
||||
public Dictionary<string, string> RefInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对象复制
|
||||
/// </summary>
|
||||
/// <param name="source">要复制其内容的来源</param>
|
||||
public void Shadow(HttpResult source)
|
||||
{
|
||||
Code = source.Code;
|
||||
Text = source.Text;
|
||||
Data = source.Data;
|
||||
RefCode = source.RefCode;
|
||||
RefText += source.RefText;
|
||||
RefInfo = source.RefInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取 <see cref="HttpResponseMessage" /> 数据
|
||||
/// </summary>
|
||||
/// <param name="response">Http响应</param>
|
||||
/// <param name="binaryMode">是否以二进制模式读取响应内容</param>
|
||||
/// <exception cref="HttpRequestException"></exception>
|
||||
internal async Task ReadAsync(HttpResponseMessage response, bool binaryMode)
|
||||
{
|
||||
ReadInfo(response);
|
||||
|
||||
if (binaryMode)
|
||||
{
|
||||
Data = await response.Content.ReadAsByteArrayAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task ReadErrorAsync(Exception exception, HttpResponseMessage response)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var e = exception;
|
||||
while (e != null)
|
||||
{
|
||||
sb.Append(e.Message + " ");
|
||||
e = e.InnerException;
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
RefText += sb.ToString();
|
||||
RefCode = (int)HttpCode.USER_UNDEF;
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
ReadInfo(response);
|
||||
Text = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadInfo(HttpResponseMessage response)
|
||||
{
|
||||
Code = (int)response.StatusCode;
|
||||
RefCode = (int)response.StatusCode;
|
||||
|
||||
if (RefInfo == null)
|
||||
{
|
||||
RefInfo = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
RefInfo.Add("ProtocolVersion", response.Version.ToString());
|
||||
|
||||
if (!string.IsNullOrEmpty(response.Content.Headers.ContentType.CharSet))
|
||||
{
|
||||
RefInfo.Add("Characterset", response.Content.Headers.ContentType.CharSet);
|
||||
}
|
||||
|
||||
if (!response.Content.Headers.ContentEncoding.Any())
|
||||
{
|
||||
RefInfo.Add("ContentEncoding", string.Join("; ", response.Content.Headers.ContentEncoding));
|
||||
}
|
||||
|
||||
RefInfo.Add("ContentType", response.Content.Headers.ContentType.ToString());
|
||||
|
||||
RefInfo.Add("ContentLength", response.Content.Headers.ContentLength.ToString());
|
||||
|
||||
foreach (var header in response.Headers) RefInfo.Add(header.Key, string.Join("; ", header.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为易读或便于打印的字符串格式
|
||||
/// </summary>
|
||||
/// <returns>便于打印和阅读的字符串</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append($"code:{Code}");
|
||||
sb.AppendLine();
|
||||
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
sb.AppendLine("text:");
|
||||
sb.AppendLine(Text);
|
||||
}
|
||||
|
||||
if (Data != null)
|
||||
{
|
||||
sb.AppendLine("data:");
|
||||
const int n = 1024;
|
||||
if (Data.Length <= n)
|
||||
{
|
||||
sb.AppendLine(Encoding.UTF8.GetString(Data));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine(Encoding.UTF8.GetString(Data, 0, n));
|
||||
sb.Append($"<--- TOO-LARGE-TO-DISPLAY --- TOTAL {Data.Length} BYTES --->");
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
sb.Append($"ref-code:{RefCode}");
|
||||
sb.AppendLine();
|
||||
|
||||
if (!string.IsNullOrEmpty(RefText))
|
||||
{
|
||||
sb.AppendLine("ref-text:");
|
||||
sb.AppendLine(RefText);
|
||||
}
|
||||
|
||||
if (RefInfo != null)
|
||||
{
|
||||
sb.AppendLine("ref-info:");
|
||||
foreach (var d in RefInfo) sb.AppendLine($"{d.Key}:{d.Value}");
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Qiniu/Qiniu.FileService.csproj
Normal file
22
Qiniu/Qiniu.FileService.csproj
Normal file
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.0;netstandard2.1;netcoreapp3.0</TargetFrameworks>
|
||||
<AssemblyName>Qiniu.FileService</AssemblyName>
|
||||
<Authors>Jackson.bruce</Authors>
|
||||
<Company>Ufangx</Company>
|
||||
<Description>File management, super large file upload, breakpoint renewal</Description>
|
||||
<licenseUrl>https://github.com/JacksonBruce/FileServices/blob/master/LICENSE</licenseUrl>
|
||||
<RepositoryUrl>https://github.com/JacksonBruce/FileServices.git</RepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/JacksonBruce/FileServices</PackageProjectUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>file service web uploader html5 uploader breakpoint renewal</PackageTags>
|
||||
<Copyright>Copyright (c) 2020-$([System.DateTime]::Now.Year) Jackson.Bruce</Copyright>
|
||||
<Version>1.0.0-beta.1</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FileServices" Version="1.0.0" />
|
||||
<PackageReference Include="Qiniu.SDK" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,22 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<AssemblyName>QiniuFileService</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Http\**" />
|
||||
<EmbeddedResource Remove="Http\**" />
|
||||
<None Remove="Http\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Qiniu.SDK" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FileService\FileServices.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
@@ -27,8 +28,40 @@ namespace TestWeb
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddFileServices(opt=>opt.DefaultScheme="")
|
||||
.AddLocalServices(o => o.StorageRootDir = hostEnvironment.ContentRootPath);
|
||||
services.AddFileServices(opt => {
|
||||
opt.DefaultScheme = "documents";//Ĭ<><C4AC><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
opt.AddAuthenticationScheme(CookieAuthenticationDefaults.AuthenticationScheme);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
//<2F>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
opt.RuleOptions = new Ufangx.FileServices.Models.FileNameRuleOptions()
|
||||
{
|
||||
Rule = Ufangx.FileServices.Models.FileNameRule.Custom,//<2F>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F2A3ACB1><EFBFBD><EFBFBD>ṩ<EFBFBD>Զ<EFBFBD><D4B6>巽<EFBFBD><E5B7BD>
|
||||
Custom = originFileName => string.Format("{0:yyyyMMddHHmmss}_xx_{1}", DateTime.Now, originFileName),
|
||||
Format = "xxx_{0:yyyyMMddHHmmss}"//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ú<EFBFBD>Rule=FileNameRule.Dateһ<65><D2BB>ʹ<EFBFBD>ã<EFBFBD>Ĭ<EFBFBD><C4AC><EFBFBD>ǣ<EFBFBD>{0:yyyyMMddHHmmss}
|
||||
};
|
||||
|
||||
})
|
||||
//<2F><>Ƭ<EFBFBD><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
.AddScheme("pictures", opt => {
|
||||
opt.StoreDirectory = "wwwroot/pictures";//ͼƬ<CDBC>洢<EFBFBD><E6B4A2>Ŀ¼
|
||||
opt.SupportExtensions = new string[] { ".jpg", ".png" };//֧<>ֵ<EFBFBD><D6B5><EFBFBD>չ<EFBFBD><D5B9>
|
||||
opt.HandlerType = null;//<2F>ϴ<EFBFBD><CFB4>ɹ<EFBFBD><C9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͱ<EFBFBD><CDB1><EFBFBD>ʵ<EFBFBD><CAB5>IFileHandler<65>ӿ<EFBFBD>
|
||||
opt.LimitedSize = 1024 * 1024 * 4;//<2F>ļ<EFBFBD><C4BC><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD>ֽ<EFBFBD>Ϊ<EFBFBD><CEAA>λ
|
||||
})
|
||||
.AddScheme("documents",opt => opt.StoreDirectory = "wwwroot/documents")//<2F>ĵ<EFBFBD><C4B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
//.AddScheme<VideoService>(name:"videos",storeDirectory:"",supportExtensions:new string[] { },LimitedSize:1024*1024*500)//<2F><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
//.AddLocalServices(o => o.StorageRootDir = hostEnvironment.ContentRootPath)//<2F><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>ϵͳ<CFB5><CDB3><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ڱ<EFBFBD><DAB1><EFBFBD>
|
||||
//<2F><>ţ<EFBFBD>洢<EFBFBD><E6B4A2><EFBFBD><EFBFBD>
|
||||
.AddQiniuFileService(opt => {
|
||||
opt.AccessKey = "";//
|
||||
opt.SecretKey = "";
|
||||
opt.BasePath = "";
|
||||
opt.Bucket = "";
|
||||
opt.Domain = "";
|
||||
opt.ChunkUnit = Qiniu.Storage.ChunkUnit.U1024K;
|
||||
opt.Zone = "ZoneCnEast";
|
||||
|
||||
});
|
||||
|
||||
services.AddControllersWithViews();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FileService\FileServices.csproj" />
|
||||
<ProjectReference Include="..\Qiniu\QiniuFileService.csproj" />
|
||||
<PackageReference Include="Qiniu.FileService" Version="1.0.0-beta.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user