HttpHandler для извлечения загружаемого файла с другого сервера?

StackOverflow https://stackoverflow.com/questions/160651

  •  03-07-2019
  •  | 
  •  

Вопрос

Я хотел бы предоставить загружаемые файлы пользователям веб-сайта, но хочу скрыть URL-адреса файлов от пользователя...Я думаю, что HttpHandler мог бы сделать это, но возможно ли получить файл с внешнего сервера и передать его пользователю?

Возможно, кто-нибудь может дать мне подсказку о том, как это сделать, или указать мне на ресурс, где это было сделано раньше?


Просто чтобы подробнее рассказать о том, чего я пытаюсь достичь...Я создаю веб-сайт ASP.NET, который содержит ссылку для скачивания музыки.Я хочу защитить фактические URL-адреса файла, и я также хочу сохранить их на внешнем сервере (PHP) (НАМНОГО дешевле)...

Итак, что мне нужно сделать, это настроить поток, который может захватывать файл с URL-адреса (указывает на другой сервер) и передавать его в объект ответа так, чтобы пользователь не осознавал, что он поступает с другого сервера.

Позволит ли метод TransmitFile передавать файл в потоковом режиме с совершенно отдельного сервера?Я не хочу, чтобы файл передавался потоком "через" мой сервер, поскольку это противоречит цели (экономия пропускной способности)...Я хочу, чтобы клиент (браузер) загрузил файл непосредственно с другого сервера.

Возможно, мне нужен обработчик на сервере файлового хостинга?Может быть, PHP-скрипт на другом конце - это правильный путь ...?

Это было полезно?

Решение

С вашим разъяснением о том, что вы хотите, чтобы пропускная способность поступала с внешнего сервера, а не с вашего, это немного меняет вопрос.

Чтобы достичь этого, на внешнем сервере должен быть веб-сайт, на который вы могли бы отправить пользователя.Вы не можете передавать файл в потоковом режиме через свой сайт, не ограничивая при этом пропускную способность, или управлять им со своего сайта, но передавать в потоковом режиме через другой сервер, поэтому он должен полностью обрабатываться через другой сайт.Проблема в том, что обычный подход, основанный на URL, показывает пользователю URL, который, как вы сказали, является вторым требованием, чтобы он не показывал URL.

Но разве вы не могли бы просто создать общую страницу, которая обслуживает файлы на внешнем сайте, и информация о том, какой файл передавать в потоковом режиме, передавалась бы через сообщение со страницы на исходном сайте?Это привело бы к удалению URL-адреса, указывающего на определенный файл.Это показало бы домен, но пользователи не смогли бы извлекать файлы, не зная полей post.

Это не обязательно должен быть HttpHandler, просто обычная страница.

Другие советы

Я рекомендую вам взглянуть на метод TransmitFile: http://msdn.microsoft.com/en-us/library/12s31dhy.aspx

Да, вы можете осуществлять потоковую передачу из удаленного потока (загружать с другого сервера) в выходной поток.Предполагать serviceUrl Сервисерл является местоположением файла для потоковой передачи:

HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
            webrequest.AllowAutoRedirect = false;
            webrequest.Timeout = 30 * 1000;
            webrequest.ReadWriteTimeout = 30 * 1000;
            webrequest.KeepAlive = false;

            Stream remoteStream = null;
            byte[] buffer = new byte[4 * 1024];
            int bytesRead;

            try {
                WebResponse responce = webrequest.GetResponse();
                remoteStream = responce.GetResponseStream();
                bytesRead = remoteStream.Read(buffer, 0, buffer.Length);

                Server.ScriptTimeout = 30 * 60;
                Response.Buffer = false;
                Response.BufferOutput = false;
                Response.Clear();
                Response.ContentType = "application/octet-stream";
                Response.AppendHeader("Content-Disposition", "attachment; filename=" + Uid + ".EML");
                if (responce.ContentLength != -1)
                    Response.AppendHeader("Content-Length", responce.ContentLength.ToString());

                while (bytesRead > 0 && Response.IsClientConnected) {
                    Response.OutputStream.Write(buffer, 0, bytesRead);
                    bytesRead = remoteStream.Read(buffer, 0, buffer.Length);
                }

            } catch (Exception E) {
                Logger.LogErrorFormat(LogModules.DomainUsers, "Error transfering message from remote host: {0}", E.Message);
                Response.End();
                return;
            } finally {
                if (remoteStream != null) remoteStream.Close();
            }

            Response.End();

Я уже делал это раньше.Во-первых, и это очевидно, файлы должны находиться в общем доступе на внешнем сервере, к которому имеет доступ пользовательский процесс веб-сайта.

Что касается HttpHandler, я справился с этим, предоставив пользователям zip-файлы, содержащие файлы, которые они хотят загрузить;таким образом, мой обработчик мог бы перехватывать любой вызов для zip-файлов и передавать им zip-файл, который я создаю.

Вот код (довольно большой кусок;Я использую MVP, поэтому он разделен на Обработчик и презентатор):Обработчик:

public class ZipDownloadModule: IHttpHandler, ICompressFilesView, IErrorView 
{
    CompressFilesPresenter _presenter;

    public ZipDownloadModule()
    {
        _presenter = new CompressFilesPresenter(this, this);
    }
    #region IHttpHandler Members

    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        OnDownloadFiles();
    }

    private void OnDownloadFiles()
    {
        if(Compress != null)
            Compress(this, EventArgs.Empty);
    }

    #endregion

    #region IFileListDownloadView Members

    public IEnumerable<string> FileNames
    {
        get 
        {
            string files = HttpContext.Current.Request["files"] ?? string.Empty;

            return files.Split(new Char[] { ',' });
        }
    }

    public System.IO.Stream Stream
    {
        get
        {
            HttpContext.Current.Response.ContentType = "application/x-zip-compressed";
            HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=ads.zip");
            return HttpContext.Current.Response.OutputStream;
        }
    }

    public event EventHandler Compress;

    #endregion

    #region IErrorView Members

    public string errorMessage
    {
        set {  }
    }

    #endregion
}

Ведущий:

public class CompressFilesPresenter: PresenterBase<ICompressFilesView>
{
    IErrorView _errorView;

    public CompressFilesPresenter(ICompressFilesView view, IErrorView errorView)
        : base(view)
    {
        _errorView = errorView;
        this.View.Compress += new EventHandler(View_Compress);
    }

    void View_Compress(object sender, EventArgs e)
    {
        CreateZipFile();
    }

    private void CreateZipFile()
    {
        MemoryStream stream = new MemoryStream();

        try
        {
            CreateZip(stream, this.View.FileNames);

            WriteZip(stream);
        }
        catch(Exception ex)
        {
            HandleException(ex);
        }
    }

    private void WriteZip(MemoryStream stream)
    {
        byte[] data = stream.ToArray();

        this.View.Stream.Write(data, 0, data.Length);
    }

    private void CreateZip(MemoryStream stream, IEnumerable<string> filePaths)
    {
        using(ZipOutputStream s = new ZipOutputStream(stream)) // this.View.Stream))
        {
            s.SetLevel(9); // 0 = store only to 9 = best compression

            foreach(string fullPath in filePaths)
                AddFileToZip(fullPath, s);

            s.Finish();
        }
    }

    private static void AddFileToZip(string fullPath, ZipOutputStream s)
    {
        byte[] buffer = new byte[4096];

        ZipEntry entry;

        // Using GetFileName makes the result compatible with XP
        entry = new ZipEntry(Path.GetFileName(fullPath));

        entry.DateTime = DateTime.Now;
        s.PutNextEntry(entry);

        using(FileStream fs = File.OpenRead(fullPath))
        {
            int sourceBytes;
            do
            {
                sourceBytes = fs.Read(buffer, 0, buffer.Length);
                s.Write(buffer, 0, sourceBytes);
            } while(sourceBytes > 0);
        }
    }

    private void HandleException(Exception ex)
    {
        switch(ex.GetType().ToString())
        {
            case "DirectoryNotFoundException":
                _errorView.errorMessage = "The expected directory does not exist.";
                break;
            case "FileNotFoundException":
                _errorView.errorMessage = "The expected file does not exist.";
                break;
            default:
                _errorView.errorMessage = "There has been an error. If this continues please contact AMG IT Support.";
                break;
        }
    }

    private void ClearError()
    {
        _errorView.errorMessage = "";
    }
}

Надеюсь, это поможет!!

Ладно, похоже, мои попытки избежать написания / развертывания какого-либо php-кода напрасны...вот с чем я собираюсь работать на файловом сервере (php):

http://www.zubrag.com/scripts/download.php

Затем ссылки с моего веб-сервера asp.net будут указывать на этот скрипт, который затем загрузит соответствующий файл (следовательно, избегая прямых загрузок и позволяя отслеживать загрузки через Google Analytics)...я думаю, это сработает

Спасибо всем Грег

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top