Обработка ошибок при загрузке файла из 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

Это для загрузки, а не загрузки, но та же концепция.

Другие вопросы по тегам