我想向网站用户提供可下载的文件,但是想要隐藏用户的文件的URL ...我认为HTTPHandler可以做到这一点,但是可以从一个文件中检索文件外部服务器并将其流式传输给用户?
也许有人可以给我一个如何实现这个目标的提示,或者指出我以前做过的资源?
只是详细说明我想要实现的目标...我正在构建一个包含音乐下载链接的ASP.NET网站。我想保护文件的实际URL,我也想将它们存储在外部(PHP)服务器上(更便宜)...
所以我需要做的是设置一个流,它可以从URL获取文件(指向另一个服务器),并将其流式传输到Response对象,而不会让用户意识到它来自另一个服务器。
TransmitFile方法是否允许从完全独立的服务器传输文件?我不希望文件通过我的服务器“流过”,因为这会破坏目的(节省带宽)...我希望客户端(浏览器)直接从其他服务器下载文件。
我是否需要文件托管服务器上的处理程序?也许另一端的PHP脚本是要走的路?...
答案 0 :(得分:1)
我建议您查看TransmitFile方法:http://msdn.microsoft.com/en-us/library/12s31dhy.aspx
答案 1 :(得分:1)
如果您希望带宽来自外部服务器而不是您的带宽,那么它会更改问题。
为了实现这一点,外部服务器必须有一个可以发送给用户的网站。您无法通过您的站点流式传输文件,但不会被带宽占用,或者从您的站点控制它,而是通过其他服务器流式传输,因此必须通过其他站点完全处理。问题是基于普通URL的方法会向用户显示URL,您说这是第二个要求它不显示URL。
但是,你不能只拥有一个通用页面来提供外部网站上的文件,并且流式传输文件的具体细节将通过原始网站页面上的帖子传递吗?这将删除指向特定文件的URL。它会显示域名,但如果不知道帖子字段,用户将无法提取文件。
这不需要是HTTPHandler,只需要是普通页面。
答案 2 :(得分:1)
是的,您可以从远程流(从其他服务器下载)流式传输到输出流。假设 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();
答案 3 :(得分:0)
我以前做过这个。首先,显然,文件必须位于网站用户进程可以访问的外部服务器上。
就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 = "";
}
}
希望这会有所帮助!!
答案 4 :(得分:0)
好吧,似乎我要避免编写/部署一些PHP代码是徒劳的......这就是我要在文件(php)服务器上运行的内容:
http://www.zubrag.com/scripts/download.php
然后我的asp.net网络服务器上的链接将指向该脚本,然后下载相关文件(因此避免直接下载,并允许通过谷歌分析跟踪下载)...我认为这样做诀窍
谢谢大家 格雷格