Обработка ошибок при загрузке файла из ASP.NET Web Handler (.ashx)
У меня есть веб-страница, с которой пользователь может загрузить файл PDF через веб-обработчик ASP.NET (.ashx
). Это реализовано как ответ в этом вопросе. У меня проблема, когда я делаю это window.top.location.href = url;
в моем JavaScript я не имею никакого реального контроля над тем, что происходит, если в обработчике возникает исключение. Пользовательский опыт, когда все работает правильно, заключается в том, что они фактически остаются на той странице, на которой они находились, и браузер сообщает им, что они могут загрузить файл PDF. Однако, когда в обработчике возникает исключение, они перенаправляются на URL обработчика и отображаются на пустой странице.
Вот пример кода, чтобы сделать его более понятным:
JavaScript:
function openPDF() {
var url = GeneratePDFUrl();
window.top.location.href = url;
}
Обработчик:
public override void Process(HttpContext context)
{
byte[] pdfdata = GetPDFData();
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("content-disposition", "attachment; filename=\"" + GetPDFFileName() + "\"");
context.Response.AddHeader("content-length", pdfdata.Length.ToString());
context.Response.BinaryWrite(pdfdata);
}
Проблема возникает, когда GetPDFData() генерирует исключение. Мы делаем все возможное, чтобы GetPDFData() не генерировала исключение, но оно генерируется из пользовательского ввода, поэтому мы также обрабатываем его здесь в случае, если есть случаи, которые мы не можем / не можем предсказать, которые генерируют ошибку.
Вот одно решение, которое я придумала, но оно показывает текст ошибки пользователя (вместо пустой страницы)
public override void Process(HttpContext context)
{
try
{
byte[] pdfdata = GetPDFData();
WritePDF(pdfdata, GetPDFFileName()); // Executes code in example above
}
catch (Exception e)
{
context.Response.Clear();
context.Response.Write(GetErrorMessage(e));
}
}
В идеале я хотел бы показать пользователям всплывающее окно, чтобы они остались на той странице, где они были.
2 ответа
Прежде всего, на этот мой ответ пользователь спрашивает, как сделать загрузку с помощью JavaScript. Но если у вас есть ссылка, которую вам не нужно добавлять в javascript, вы также можете добавить ее, используя обычную ссылку для скачивания.
В настоящее время многие веб-сайты используют страницу с текстом, на котором написано "и теперь ваша загрузка начнется через несколько секунд. Если не начнется, нажмите здесь, бла-бла-бла". Одна из причин похожа на вашу: пользователь должен знать, что что-то начнет загрузку через несколько секунд, а если нет, то пользователь поймет, что существует проблема с другим дополнительным сообщением.
В общем, когда вы собираетесь отправить файл для загрузки, вы больше не находитесь на странице, вы не можете отправить сообщение в середине загрузки, - или когда файл заканчивается на pdf, то, вероятно, ничего не показывает на веб-странице. Так что, с моей точки зрения, если у вас есть проблемы и выдается исключение, вам нужно разработать несколько шагов, чтобы сообщить пользователю, что что-то идет не так - как средняя страница, которая информирует пользователя, что "теперь вы собираетесь получить файл". - если файл не начнется загрузка через несколько секунд, пожалуйста, сделайте это "
Однако, когда в обработчике возникает исключение, они перенаправляются на URL обработчика и отображаются на пустой странице.
Чтобы избежать этой черной страницы, при ошибке вы можете вернуть этот код, и пользователь остается на странице как есть, но все равно не получил никакого сообщения об ошибке.
Response.TrySkipIisCustomErrors = true;
Response.Status = "204 No Content";
Response.StatusCode = 204;
Response.End();
В качестве альтернативы вы можете попытаться перенаправить его на страницу ошибки, используя
Response.Redirect("errorpage.aspx");
и, возможно, вы можете отправить и некоторые идентификаторы ошибок там.
Вы также можете попробовать показать простое сообщение как
context.Response.ContentType = "text/html";
context.Response.Write("Error downloading file - Please contact with us");
Как насчет того, чтобы вместо установки href окна установить src скрытого iframe. Затем вы можете сделать некоторую хитрость с возвращенным значением в скрытом iframe, например:
context.Response.Clear();
context.Response.Write("<script>alert('" + GetErrorMessage(e) + "');</script>");
Этот грубый пример просто предупредит об ошибке. Если вы находитесь в одном домене (а я подозреваю, что вы есть!), То вы можете стать более умным, вместо того, чтобы предупреждать, вызывая метод в родительском объекте, например
context.Response.Clear();
context.Response.Write("<script>window.parent.someFunction('" + GetErrorMessage(e) + "');</script>");
Вот пример, который я нашел на SO, который делает именно это: Получение кода состояния HTTP из загруженного iframe с помощью Javascript
Это для загрузки, а не загрузки, но та же концепция.