Pregunta

Me gustaría proporcionar archivos descargables a los usuarios del sitio web, pero quiero ocultar la URL de los archivos al usuario ... Estoy pensando que un HTTPHandler podría hacer el truco, pero ¿es posible recuperar un archivo de un ¿Servidor externo y transmitirlo al usuario?

Tal vez alguien pueda darme una pista sobre cómo lograr esto o indicarme un recurso donde se haya hecho anteriormente.


Solo para explicar lo que estoy tratando de lograr ... Estoy construyendo un sitio web ASP.NET, que contiene un enlace de descarga de música. Quiero proteger las URL reales del archivo, y también quiero almacenarlas en un servidor externo (PHP) (MUCHO MÁS barato) ...

Entonces, lo que debo hacer es configurar una secuencia que pueda tomar el archivo de una URL (apunta a otro servidor), y transmitirla al objeto Respuesta sin que el usuario se dé cuenta de que proviene de otro servidor.

¿El método TransmitFile permitirá la transmisión de un archivo desde un servidor completamente separado? No quiero que el archivo se transmita " a través de " Mi servidor, ya que anula el propósito (guardar ancho de banda) ... Quiero que el cliente (navegador) descargue el archivo directamente desde el otro servidor.

¿Necesito un controlador en el servidor de alojamiento de archivos, tal vez? Tal vez un script PHP en el otro extremo sea el camino a seguir ...?

¿Fue útil?

Solución

Con su aclaración de que desea que el ancho de banda provenga del servidor externo y no del suyo, cambia la pregunta un poco.

Para lograr esto, el servidor externo tendría que tener un sitio web al que enviar al usuario. No puede transmitir el archivo a través de su sitio, pero no puede recibir acceso al ancho de banda, ni puede controlarlo desde su sitio sino que se transmite a través del otro servidor, por lo que debe manejarse completamente a través del otro sitio. El problema es que un enfoque basado en una URL normal le mostraría al usuario la URL, que dijo que es el segundo requisito que no muestra la URL.

Pero, ¿no podría simplemente tener una página genérica que sirva los archivos en el sitio externo, y los detalles sobre qué archivo se transmitiría a través de una publicación de la página en el sitio original? Eso eliminaría la URL que apunta a un archivo específico. Mostraría el dominio, pero los usuarios no podrían extraer archivos sin conocer los campos de publicación.

Esto no tendría que ser un HTTPHandler, solo una página normal.

Otros consejos

Le recomiendo que consulte el método TransmitFile: http: // msdn. microsoft.com/en-us/library/12s31dhy.aspx

Sí, puede transmitir desde un flujo remoto (descargar desde otro servidor) al flujo de salida. Supongamos que serviceUrl es la ubicación del archivo para transmitir:

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();

He hecho esto antes. Primero, y obviamente, los archivos deben estar en un recurso compartido en el servidor externo al que el proceso de usuario del sitio web tiene acceso.

En cuanto al HTTPHandler, manejé esto dando a los usuarios archivos zip que contenían los archivos que querían descargar; de esta manera mi manejador podría interceptar cualquier llamada para archivos .zip y transmitirlos al archivo zip que creo.

Aquí está el código (una buena parte; yo uso MVP, por lo que se divide en Handler y Presenter): Controlador:

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
}

Presentador:

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 = "";
    }
}

Espero que esto ayude !!

Bueno, parece que mi búsqueda para evitar escribir / implementar algún código php es en vano ... esto es lo que voy a ejecutar en el servidor de archivos (php):

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

Luego, los enlaces de mi servidor web asp.net apuntarán a ese script, que luego descargará el archivo relevante (evitando así descargas directas y permitiendo el seguimiento de descargas a través de Google Analytics) ... creo que eso funcionará el truco

Gracias a todos Greg

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top