在某些場合,需要臨時將一個文件存儲到一個可被公網訪問的地方,某個服務需要訪問一下這個文件。這個文件基本上就是一次壽命,也就是你上傳一下,然后被訪問一下,這個文件的壽命就結束了。
對于這種需求,自建服務程序,太麻煩。剛好,阿里云提供了這樣的服務。其實就三個步驟:
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);