HTTPHandler pour récupérer le fichier de téléchargement à partir d'un autre serveur?
-
03-07-2019 - |
Question
Je souhaite fournir des fichiers téléchargeables aux utilisateurs du site Web, mais je souhaite masquer l'URL des fichiers à l'utilisateur ... Je pense qu'un gestionnaire HTTPHandler pourrait faire l'affaire, mais est-il possible de récupérer un fichier à partir d'un fichier. serveur externe et le diffuser à l'utilisateur?
Peut-être que quelqu'un pourrait me donner un indice sur la façon de procéder, ou me diriger vers une ressource où cela avait été fait auparavant?
Pour en savoir plus sur ce que je tente d’atteindre ... Je construis un site Web ASP.NET, qui contient un lien de téléchargement de musique. Je souhaite protéger les URL réelles du fichier et les stocker sur un serveur externe (PHP) (BEAUCOUP BEAUCOUP moins cher) ...
Je dois donc configurer un flux capable de récupérer le fichier depuis une URL (pointant vers un autre serveur) et de le diffuser vers l'objet Response sans que l'utilisateur ne réalise qu'il provient d'un autre serveur.
La méthode TransmitFile permettra-t-elle la diffusion en continu d'un fichier à partir d'un serveur complètement séparé? Je ne souhaite pas que le fichier soit transféré " par le biais de " mon serveur, car cela va à l'encontre de l'objectif (économie de bande passante) ... Je souhaite que le client (navigateur) télécharge le fichier directement depuis l'autre serveur.
Ai-je peut-être besoin d'un gestionnaire sur le serveur d'hébergement de fichiers? Peut-être qu’un script PHP à l’autre bout serait la solution ...?
La solution
Si vous souhaitez préciser que la bande passante doit provenir du serveur externe et non du vôtre, la question change un peu.
Pour ce faire, le serveur externe devrait avoir un site Web sur lequel vous pourriez envoyer l'utilisateur. Vous ne pouvez pas diffuser le fichier via votre site sans vous faire toucher par la bande passante, ni le contrôler depuis votre site, mais le diffuser via l'autre serveur. Il doit donc être entièrement géré via l'autre site. Le problème avec cela est une approche basée sur une URL normale qui montrerait à l’URL l’URL, ce qui, selon vous, est la deuxième condition requise pour ne pas afficher l’URL.
Mais, ne pourriez-vous pas simplement avoir une page générique qui sert les fichiers sur le site externe et les détails sur le fichier à diffuser qui serait transmis via une publication de la page du site d'origine? Cela supprimerait l'URL pointant sur un fichier spécifique. Cela montrerait le domaine, mais les utilisateurs ne pourraient pas extraire des fichiers sans connaître les champs de publication.
Cela n'aurait pas besoin d'être un HTTPHandler, mais une page normale.
Autres conseils
Je vous recommande de consulter la méthode TransmitFile: http: // msdn. microsoft.com/en-us/library/12s31dhy.aspx
Oui, vous pouvez diffuser depuis un flux distant (téléchargement depuis un autre serveur) vers le flux de sortie. Supposons que serviceUrl correspond à l'emplacement du fichier à diffuser:
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();
Je l'ai déjà fait auparavant. Tout d’abord, il est évident que les fichiers doivent se trouver sur un partage sur le serveur externe auquel le processus utilisateur du site Web a accès.
Pour ce qui est de HTTPHandler, j’ai traité cela en donnant aux utilisateurs des fichiers zip contenant les fichiers qu’ils veulent télécharger; Ainsi, mon gestionnaire pourra intercepter tout appel de fichiers .zip et les diffuser en streaming avec le fichier zip que je crée.
Voici le code (un morceau assez important; j'utilise MVP, il est donc divisé en gestionnaire et présentateur): Gestionnaire:
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
}
Présentateur:
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 = "";
}
}
J'espère que ça aide !!
D'accord, ma quête pour éviter d'écrire / déployer du code php est en vain ... voici ce que je vais exécuter sur le serveur de fichiers (php):
http://www.zubrag.com/scripts/download.php
Ensuite, les liens de mon serveur Web asp.net pointeront vers ce script, qui téléchargera ensuite le fichier approprié (évitant ainsi les téléchargements directs et permettant le suivi des téléchargements via Google Analytics) ... Je pense que cela suffira. le truc
Merci à tous Greg