【问题标题】:HTTPHandler to Retrieve Download File from another server?HTTPHandler 从另一台服务器检索下载文件?
【发布时间】:2008-10-02 02:38:10
【问题描述】:

我想向网站用户提供可下载的文件,但想对用户隐藏文件的 URL...我认为 HTTPHandler 可以解决问题,但是否可以从外部服务器并将其流式传输给用户?

也许有人可以给我一个提示,告诉我如何做到这一点,或者指出我以前做过的资源?


只是为了详细说明我想要实现的目标......我正在构建一个 ASP.NET 网站,其中包含一个音乐下载链接。我想保护文件的实际 URL,并且我还想将它们存储在外部(PHP)服务器上(便宜得多)......

所以我需要做的是设置一个流,它可以从 URL(指向另一个服务器)获取文件,并将其流式传输到 Response 对象,而用户不会意识到它来自另一个服务器。

TransmitFile 方法是否允许从完全独立的服务器流式传输文件?我不希望文件“通过”我的服务器流式传输,因为这违背了目的(节省带宽)......我希望客户端(浏览器)直接从另一台服务器下载文件。

我是否需要文件托管服务器上的处理程序?也许另一端的 PHP 脚本是要走的路……?

【问题讨论】:

    标签: asp.net download httphandler


    【解决方案1】:

    您明确表示希望带宽来自外部服务器而不是您的服务器,这大大改变了问题。

    为了实现这一点,外部服务器上必须有一个网站,您可以将用户发送到该网站。您不能通过您的站点流式传输文件但不会受到带宽的影响,或者无法从您的站点控制它但通过其他服务器流式传输,因此必须通过其他站点完全处理它。问题在于,基于 URL 的普通方法会向用户显示 URL,您所说的第二个要求是它不显示 URL。

    但是,您难道不能只有一个通用页面来提供外部站点上的文件,而关于要流式传输的文件的细节将通过原始站点页面上的帖子传递吗?这将删除指向特定文件的 URL。它会显示域,但用户将无法在不知道帖子字段的情况下提取文件。

    这不需要是一个 HTTPHandler,只是一个普通页面。

    【讨论】:

    • 感谢 Carlton... 这个解决方案听起来可行.. 所以澄清一下,您建议将表单帖子传递给其他服务器,并将文件详细信息作为隐藏表单元素下载?虽然这会起作用,但它不是万无一失的......而且我仍然需要编写一些 php 代码。会调查的谢谢
    【解决方案2】:

    推荐你看一下TransmitFile方法:http://msdn.microsoft.com/en-us/library/12s31dhy.aspx

    【讨论】:

    • 这就是我所追求的,但找不到太多关于它的信息(例如,它会从外部 URL 传输文件还是该文件必须与代码?)
    【解决方案3】:

    是的,您可以从远程流(从另一台服务器下载)流式传输到输出流。假设 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();
    

    【讨论】:

      【解决方案4】:

      我以前做过。首先,很明显,文件必须位于网站用户进程可以访问的外部服务器上的共享中。

      就 HTTPHandler 而言,我通过为用户提供包含他们想要下载的文件的 zip 文件来处理这个问题;这样,我的处理程序就可以拦截对 .zip 文件的任何调用,并将它们流式传输到我创建的 zip 文件中。

      这是代码(相当大的一部分;我使用 MVP,所以它分为 Handler 和 Presenter): 处理程序:

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

      希望这会有所帮助!

      【讨论】:

        【解决方案5】:

        好吧,看来我避免编写/部署一些 php 代码的努力是徒劳的……这是我要在文件 (php) 服务器上运行的内容:

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

        然后来自我的 asp.net 网络服务器的链接将指向该脚本,然后该脚本将下载相关文件(因此避免直接下载,并允许通过谷歌分析跟踪下载)...我认为可以诀窍

        谢谢大家 格雷格

        【讨论】:

          猜你喜欢
          • 2019-04-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-16
          • 2016-10-18
          相关资源
          最近更新 更多