在某些场合,需要临时将一个文件存储到一个可被公网访问的地方,某个服务需要访问一下这个文件。这个文件基本上就是一次寿命,也就是你上传一下,然后被访问一下,这个文件的寿命就结束了。
对于这种需求,自建服务程序,太麻烦。刚好,阿里云提供了这样的服务。其实就三个步骤:
1、创建一个临时存放的位置
2、上传文件
3、获取这个临时存放的位置对应的公网URL
然后将这个URL提供给某个服务就可以了 ,文件大约保存1个小时。那么这个文件的有效期也就是一个小时,基本上够用了。
接下来,按照如下编码,即可使用此功能。
获取临时文件上传地址
private static Client CreateHbrClient()
{
return new Client(new Config
{
AccessKeyId = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID"),
AccessKeySecret = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET"),
Endpoint = "hbr.cn-hangzhou.aliyuncs.com"
});
}
private static CreateTempFileUploadUrlResponse? UploadFileToTempStorage(string filePath)
{
Client client = CreateHbrClient();
try
{
return client.CreateTempFileUploadUrlWithOptions(new CreateTempFileUploadUrlRequest
{
FileName = Path.GetFileName(filePath)
},
new RuntimeOptions()
);
}
catch (Exception error)
{
Console.WriteLine(error.Message);
Console.WriteLine(error.Data["Recommend"]);
}
return null;
}
上载临时文件
正在实现C#代码(这里试了很多次(HttpClient、WebClient),都没搞定,最后用最原始的方式组装数据才能用)。但是Python代码不会遇到问题。
public static void PostFile1(string filePath, CreateTempFileUploadUrlResponse data)
{
//提交文件
Console.WriteLine("curl -X POST ^");
Console.WriteLine("-F \"OSSAccessKeyId=" + data.Body.OssAccessKeyId + "\" ^");
Console.WriteLine("-F \"Signature=" + data.Body.Signature + "\" ^");
Console.WriteLine("-F \"Policy=" + data.Body.Policy + "\" ^");
Console.WriteLine("-F \"key=" + data.Body.TempFileKey + "\" ^");
Console.WriteLine("-F \"file=@" + filePath + "\" ^");
Console.WriteLine($"https://{data.Body.BucketName}.{data.Body.Endpoint}/");
Console.WriteLine("");
Console.ReadLine();
}
public static void PostFileAsync(string filePath, CreateTempFileUploadUrlResponse data)
{
//PostFile1(filePath, data);
var uploadUrl = $"https://{data.Body.BucketName}.{data.Body.Endpoint}/";
string host = $"{data.Body.BucketName}.{data.Body.Endpoint}";
string boundary = "---------------------------boundary";
string contentType = "multipart/form-data; boundary=" + boundary;
// 构造请求头
string requestHeader = $"POST / HTTP/1.1\r\n";
requestHeader += $"Host: {host}\r\n";
requestHeader += $"Content-Type: {contentType}\r\n";
requestHeader += "Connection: close\r\n";
// 构造请求体
StringBuilder requestBody = new StringBuilder();
requestBody.AppendLine($"--{boundary}");
requestBody.AppendLine("Content-Disposition: form-data; name=\"OSSAccessKeyId\"");
requestBody.AppendLine();
requestBody.AppendLine(data.Body.OssAccessKeyId);
requestBody.AppendLine($"--{boundary}");
requestBody.AppendLine("Content-Disposition: form-data; name=\"Signature\"");
requestBody.AppendLine();
requestBody.AppendLine(data.Body.Signature);
requestBody.AppendLine($"--{boundary}");
requestBody.AppendLine("Content-Disposition: form-data; name=\"Policy\"");
requestBody.AppendLine();
requestBody.AppendLine(data.Body.Policy);
requestBody.AppendLine($"--{boundary}");
requestBody.AppendLine("Content-Disposition: form-data; name=\"key\"");
requestBody.AppendLine();
requestBody.AppendLine(data.Body.TempFileKey);
requestBody.AppendLine($"--{boundary}");
requestBody.AppendLine("Content-Disposition: form-data; name=\"file\"; filename=\"" + Path.GetFileName(filePath) + "\"");
requestBody.AppendLine("Content-Type: audio/m4a");
requestBody.AppendLine();
byte[] requestBodyBytes = Encoding.UTF8.GetBytes(requestBody.ToString());
// 读取文件内容
byte[] fileBytes = File.ReadAllBytes(filePath);
// 构造完整的请求数据
byte[] requestBytes = new byte[requestBodyBytes.Length + fileBytes.Length + Encoding.UTF8.GetBytes($"\r\n--{boundary}--\r\n").Length];
requestBodyBytes.CopyTo(requestBytes, 0);
fileBytes.CopyTo(requestBytes, requestBodyBytes.Length);
Encoding.UTF8.GetBytes($"\r\n--{boundary}--\r\n").CopyTo(requestBytes, requestBodyBytes.Length + fileBytes.Length);
// 发送请求
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
IPAddress ipAddress = Dns.GetHostEntry(host).AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 443);
socket.Connect(remoteEP);
// 使用SslStream封装Socket连接
using (SslStream sslStream = new SslStream(new NetworkStream(socket), false, (object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)=>true))
{
sslStream.AuthenticateAsClient(host);
// 发送请求头
byte[] headerBytes = Encoding.UTF8.GetBytes(requestHeader + $"Content-Length: {requestBytes.Length}\r\n\r\n");
sslStream.Write(headerBytes);
// 发送请求体
sslStream.Write(requestBytes);
// 接收响应
byte[] buffer = new byte[1024];
int bytesRead;
StringBuilder response = new StringBuilder();
while ((bytesRead = sslStream.Read(buffer, 0, buffer.Length)) > 0)
{
response.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
}
Console.WriteLine("Response:");
Console.WriteLine(response.ToString());
}
}
}
获取文件路径
public static string? GetUrl(string filePath, CreateTempFileUploadUrlResponse data)
{
Client client = CreateHbrClient();
try
{
return client.GetTempFileDownloadLinkWithOptions(new GetTempFileDownloadLinkRequest
{
TempFileKey = data.Body.TempFileKey,
},
new RuntimeOptions()
).Body.Url;
}
catch (Exception error)
{
Console.WriteLine(error.Message);
Console.WriteLine(error.Data["Recommend"]);
}
return null;
}
}
执行代码
const string filePath = "C:\\Users\\Zmrbak\\Documents\\Camtasia\\声线20250513-26.m4a";
//获取临时文件上传地址
var urlResponse = UploadFileToTempStorage(filePath);
if (urlResponse == null) return;
//上载临时文件
await PostFileAsync(filePath, urlResponse);
//获取文件路径
var url = GetUrl(filePath, urlResponse);
Console.WriteLine(url);