HttpWebResponse отключает рано при загрузке большого файла
Я использую клиентский класс C#, предоставляемый USPS EPF (Electronic Product Fulfillment) для загрузки файлов USPS через консольное приложение. Я использую консольное приложение для входа с учетными данными USPS, указываю файл, который хочу загрузить, и получаю файл. Все это прекрасно работает для двух небольших файлов, к которым у нас есть доступ (AMS Developer Kit, 47,7 МБ и DPV Developer Kit, 1,59 МБ). Однако, когда я пытаюсь загрузить файл AMS Commercial DVD объемом 2,8 ГБ, который является единственным, который меня действительно волнует, у меня возникают проблемы. Консольное приложение перестает загружать файл каждый раз по 1,75 ГБ. Так как это файл.tar, я могу открыть его и посмотреть его содержимое, но, естественно, многое отсутствует. Класс Client, предоставленный USPS, не вызывает исключений или ошибок любого рода; он должен читать до конца файла, но он просто останавливается рано.
Я перепробовал все, что мог придумать: изменить свойства HttpWebRequest (изменить KeepAlive на true, увеличить значение Timeout), изменить метод getEpfFile, чтобы использовать IsolatedStorageFile вместо MemoryStream, чтобы получить файл, даже проверить с нашими сетевыми специалистами, чтобы сделать уверен, что нет какой-либо произвольной настройки сети, вызывающей тайм-аут Я пытался загрузить с моей машины и с разных сетевых серверов один и тот же результат. Вместо этого я изучил использование WebClient, но для этого требуется параметр полного URL-адреса файла для загрузки, который неизвестен. Насколько я могу судить, я должен использовать HttpWebRequest для доступа к файлам USPS EPF.
Это метод getEpfFile из класса Client.cs, предоставленного USPS (извиняюсь за любые проблемы с форматированием, это мой первый пост на сайте):
// получить актуальный файл
public bool getEpfFile(String fileid)
{
bool downloadSuccess = true;
string strUrl = this.strBaseUrl + "/download/epf";
try
{
Console.WriteLine("Starting file download ...");
// add json to URL
Dictionary<string, string> json_value = new Dictionary<string, string>();
json_value.Add("logonkey", this.logon_key);
json_value.Add("tokenkey", this.token_key);
json_value.Add("fileid", fileid);
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
string json_string = "obj=" + jsonSerializer.Serialize(json_value);
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] byteArray = encoding.GetBytes(json_string);
// set URL
Uri address = new Uri(strUrl);
// web request
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.UserAgent = "USPS .NET Sample";
request.KeepAlive = false;
request.Timeout = 100000;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
request.ContentLength = byteArray.Length;
request.ContentType = "application/x-www-form-urlencoded";
// add headers
// request.Headers.Add("Akamai-File-Request", filepath);
request.Headers.Add("logonkey", this.logon_key);
request.Headers.Add("tokenkey", this.token_key);
request.Headers.Add("fileid", fileid);
// post request
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
// Get response
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
if (request.HaveResponse == true && response != null)
{
Stream remoteStream = response.GetResponseStream();
Directory.CreateDirectory("c:\\Atemp");
Stream localStream = File.Create("c:\\Atemp\\dd.tar");
//byte[] buffer = new byte[2048];
byte[] buffer = new byte[1000000];
int bytesRead = 0;
do
{
// Read data (up to 1k) from the stream
bytesRead = remoteStream.Read(buffer, 0, buffer.Length);
// Write the data to the local file
localStream.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
int i = response.Headers.Count;
for (int x = 0; x < i; x++)
{
if (response.Headers.Keys[x].ToString() == "User-Tokenkey")
{
this.token_key = response.Headers[x].ToString();
}
else if (response.Headers.Keys[x].ToString() == "User-Logonkey")
{
this.logon_key = response.Headers[x].ToString();
}
else if (response.Headers.Keys[x].ToString() == "Service-Response")
{
Console.WriteLine("Web service result: " + response.Headers[x].ToString());
}
else if (response.Headers.Keys[x].ToString() == "Service-Messages")
{
Console.WriteLine("Resulting Messages: " + response.Headers[x].ToString());
}
}
// close resources
localStream.Close();
remoteStream.Close();
response.Close();
Console.WriteLine("File Download completed.");
}
}
catch (Exception ex)
{
downloadSuccess = false;
string str = ex.Message;
str += "";
}
return downloadSuccess;
}
Любая идея о том, почему он продолжает обрезать рано, будет высоко ценится.
3 ответа
Оказалось, что в USPS была программа Download Manager, которая выполняет то, что я пытаюсь сделать, в 10 раз проще. Я был отправлен по электронной почте почтовый файл непосредственно представителем USPS, но документация (включая ссылку для скачивания) доступна здесь, если кому-то это нужно: https://ribbs.usps.gov/acs/documents/tech_guides/ACS_EPF_DownloadManagerTechnicalGuide.pdf
Некоторое время назад я столкнулся с той же проблемой, выяснилось, что файл был на самом деле на сервере AKAMAI, а не на сервере EPF, что и является причиной проблемы. Это больше, чем 2 ГБ, тогда больше всего шансов, что он находится на сервере AKAMAI, поэтому я даю код, который работал для меня, как показано ниже,
public static bool DownloadEPFByFileIDUsingNewList(ref USPSUserDTO obj, USPSProductsDTO productList)
{
USPSFileDTO userDTO = new USPSFileDTO();
if (obj != null)
{
foreach (var product in productList.fileList)
{
product.productcode = "NCAW";
product.productid = "NCL18H";
downloadSelectedFile(product, ref obj);
}
}
return true;
}
private static void downloadSelectedFile(USPSProductInfo uspsProductDownload, ref USPSUserDTO obj)
{
string serviceResponse = string.Empty;
string serviceMessages = string.Empty;
USPSProductInfo uspsProductInfo = uspsProductDownload;
int downloadPercentage = 0;
bool isAkamaiFile = IsAkamaiFile(uspsProductDownload.productcode); //true;
try
{
string[] statusResponse = SetStatus(USPS_URL, VERSION, obj.logonkey, obj.tokenkey, "S", uspsProductInfo.fileid, obj.login, obj.pword);
if (statusResponse != null)
{
obj.logonkey = statusResponse[0];
obj.tokenkey = statusResponse[1];
}
Uri StatusURL = new Uri(USPS_URL + (isAkamaiFile ? "/download/file" : "/download/epf"));
byte[] byteLength = new ASCIIEncoding().GetBytes("obj=" + new JavaScriptSerializer().Serialize((object)new Dictionary<string, string>()
{
{
"logonkey",
obj.logonkey
},
{
"tokenkey",
obj.tokenkey
},
{
"fileid",
uspsProductInfo.fileid
}
}));
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(StatusURL);
httpWebRequest.UserAgent = "EPF Download Manager - " + VERSION;
httpWebRequest.KeepAlive = false;
httpWebRequest.Timeout = 100000;
httpWebRequest.Method = METHOD_TYPE;
httpWebRequest.ContentLength = (long)byteLength.Length;
httpWebRequest.ContentType = CONTENT_TYPE;
(httpWebRequest.Headers).Add("Akamai-File-Request", uspsProductInfo.filepath + uspsProductInfo.filename);
(httpWebRequest.Headers).Add("logonkey", obj.logonkey);
(httpWebRequest.Headers).Add("tokenkey", obj.tokenkey);
(httpWebRequest.Headers).Add("fileid", uspsProductInfo.fileid);
//TODO chage path
string path = @"C:\try\newZipFiles" + "\\" + uspsProductInfo.fulfilled;
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
string outputFilePath = path + "\\" + uspsProductInfo.filename;
Stream stream = ((WebRequest)httpWebRequest).GetRequestStream();
stream.Write(byteLength, 0, byteLength.Length);
stream.Close();
HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
int headercount = httpWebResponse.Headers.Count;
for (int headCount = 0; headCount < headercount; ++headCount)
{
if ((httpWebResponse.Headers.Keys[headCount]).ToString() == "User-Tokenkey")
{
string responseToken = (httpWebResponse.Headers)[headCount].ToString();
if (responseToken.Contains(","))
{
responseToken = responseToken.Replace(",", "").Trim();
}
obj.tokenkey = responseToken.Trim();
}
else if ((httpWebResponse.Headers.Keys[headCount]).ToString() == "User-Logonkey")
{
string responseLogonkey = ((httpWebResponse.Headers)[headCount]).ToString();
if (responseLogonkey.Contains(","))
responseLogonkey = responseLogonkey.Replace(",", "");
obj.logonkey = responseLogonkey.Trim();
}
else if ((httpWebResponse.Headers.Keys[headCount]).ToString() == "Service-Response")
serviceResponse = ((httpWebResponse.Headers)[headCount]).ToString().Replace(",", "").Trim();
else if ((httpWebResponse.Headers.Keys[headCount]).ToString() == "Service-Messages")
serviceMessages = ((httpWebResponse.Headers)[headCount]).ToString();
}
if (serviceResponse == "success")
{
long countr = 0;
Stream streamResponse = httpWebResponse.GetResponseStream();
Stream fileStream = (Stream)System.IO.File.Create(outputFilePath);
long downloadedFileSize = 0L;
long originalFileSize = long.Parse(uspsProductInfo.filesize);
byte[] bufferSize = isAkamaiFile ? new byte[1024] : new byte[512];
int bytesRead = streamResponse.Read(bufferSize, 0, bufferSize.Length);
try
{
while (bytesRead > 0)
{
countr++;
fileStream.Write(bufferSize, 0, bytesRead);
downloadedFileSize += (long)bytesRead;
downloadPercentage = (int)(downloadedFileSize * 100L / originalFileSize);
bytesRead = streamResponse.Read(bufferSize, 0, bufferSize.Length);
Console.Clear();
Console.WriteLine("Downloaded " + downloadedFileSize + " of " + originalFileSize + " bytes." + " " + downloadPercentage + "%" + "counter" + countr);
}
}
catch (Exception)
{
}
fileStream.Close();
streamResponse.Close();
httpWebResponse.Close();
if (downloadedFileSize == long.Parse(uspsProductInfo.filesize))
{
string[] statusCompleted = SetStatus(USPS_URL, VERSION, obj.logonkey, obj.tokenkey, "C", uspsProductInfo.fileid, obj.login, obj.pword);
if (statusCompleted != null)
{
obj.logonkey = statusCompleted[0];
obj.tokenkey = statusCompleted[1];
}
}
}
ExtractRarFile(outputFilePath, uspsProductInfo.fulfilled, path);
}
catch (Exception exception_0)
{
}
finally
{
}
}
public static bool IsAkamaiFile(string productCodeIn)
{
return productCodeIn == "AISVR" || productCodeIn == "AMS" || (productCodeIn == "NCAW" || productCodeIn == "NCAWM") || productCodeIn == "NCAM";
}
Проверьте с вашим кодом продукта и попробуйте это, он будет работать с некоторыми изменениями с вашим кодом продукта. Удачи.
Ваш тайм-аут установлен всего чуть более одной минуты... вы можете скачать так быстро? Увеличьте время ожидания и попробуйте снова. (будьте осторожны, это в миллисекундах)