1

我似乎找不到我的问题的有效答案,我想知道是否有人可以提供帮助。基本上我的网站上有一个链接,可以下载一个 zip 文件:

http://***.com/download.php?id=1

如果您在网页上激活此链接,它将弹出另存为对话框,并让您使用默认名称保存文件ThisIsMyZipFile.zip

我的问题是,在 c# 下,如果我使用new Uri("http://***.com/download.pgp?id=1").IsFile它会返回false,所以如果不执行 awebclient DownloadString并查看前两个字节是否为PK.

此外,即使手动下载为字符串检测PK标题并保存文件,我也无法找出我的网站想要使用的默认文件名,ThisIsMyZipFile.zip因为我想使用相同的文件名。

请问有人知道解决这两个问题的好方法吗?

更新

感谢 Paul 和他的回答,我创建了以下函数,它完全符合我的需要:

/// <summary>
/// Returns the responded HTTP headers of the given URL and if the link refers to the file it returns extra information about it.
/// </summary>
/// <param name="Url">The address.</param>
/// <returns>
/// null if a WebException is thrown
/// otherwise:
/// List of headers:
///     Keep-Alive          - Timeout value (i.e. timeout=2, max=100)
///     Connection          - The type of connection (i.e. Keep-Alive)
///     Transfer-Encoding   - The type of encoding used for the transfer (i.e. chunked)
///     Content-Type        - The type of Content that will be transferred (i.e. application/zip)
///     Date                - The servers date and time
///     Server              - The server that is handling the request (i.e. Apache)
///     AbsoluteUri         - The full Uri of the resulting link that will be followed.
/// The following key will be present if the link refers to a file
///     Filename            - The filename (not path) of the file that will be downloaded if the link if followed.
/// </returns>
public Dictionary<string, string> GetHTTPResponseHeaders(string Url)
{
    WebRequest WebRequestObject = HttpWebRequest.Create(Url);
    WebResponse ResponseObject = null;
    try
    {
        ResponseObject = WebRequestObject.GetResponse();
    }
    catch(WebException ex)
    {
        return null;
    }
    // Add the header inforamtion to the resulting list
    Dictionary<string, string> HeaderList = new Dictionary<string, string>();
    foreach (string HeaderKey in ResponseObject.Headers)
        HeaderList.Add(HeaderKey, ResponseObject.Headers[HeaderKey]);

    // Add the resolved Uri to the resulting list
    HeaderList.Add("AbsoluteUri", ResponseObject.ResponseUri.AbsoluteUri);

    // If this is a zip file then add the download filename specified by the server to the resulting list
    if (ResponseObject.ContentType.ToLower() == "application/zip")
    {
        HeaderList.Add("Filename", ResponseObject.ResponseUri.Segments[ResponseObject.ResponseUri.Segments.Length-1]);
    }

    // We are now finished with our response object
    ResponseObject.Close();

    // Return the resulting list
    return HeaderList;
}

4

2 回答 2

2

Uri.IsFile对 URI 执行静态检查,即查看“方案”部分(包括冒号的第一位)是否为file:. 它不查看通过请求驻留在 URI 中的资源返回的实际内容。(事实上​​,因为它实际上根本没有尝试联系服务器,所以 URI 实际上可能指向丢失的资源,但IsFile仍然可以工作。)

如果您想查看资源的内容是否属于特定类型,那么您必须:

  1. 检索资源的 HTTP 标头(如果它是 HTTP 或 HTTPS 资源:即,如果“方案”是httphttps)。
  2. 检索(至少部分)资源并检查它。

您当前正在执行 2,但是对于 HTTP 资源(带有 HTTP URL),执行 1 会更干净、更便宜。您可以通过执行 HTTPHEAD请求来执行此操作(与GETor POST、&c 相对)。这将返回 HTTP 标头而不返回资源本身。代码看起来像:

var request = WebRequest.Create("http://somewhere.overtherainbow.com/?a=b");
request.Method = "HEAD";
WebResponse response = request.GetResponse();
//TODO check status code
string contentType = response.ContentType;
response.Close();

内容类型将为您提供文件类型的一些指示,但许多二进制文件将仅作为八位字节流返回,因此如果您希望区分不同的二进制文件,您可能仍需要检索和检查资源本身的魔术字节文件类型。(内容类型应该足以让您区分二进制文件和网页。)

因此,完整的解决方案可能是:

  1. 发送GET资源请求。
  2. 检查响应状态以确保没有错误。
  3. 检查内容类型标头以查看我们是否有二进制八位字节流。
  4. 从响应流中读取两个字节以查看文件是否以“PK”开头。
于 2012-12-27T11:19:23.430 回答
1

如果没有实际向该 URL 发送 HTTP 请求,您绝对无法检测到给定 URL 会导致文件被下载。

现在到第二个问题。您可以发送 HTTP 请求来下载文件,然后检查包含文件名的 Content-Disposition 标头:

using (var client = new WebClient())
{
    using (var stream = client.OpenRead("http://*.com/download.php?id=1"))
    {
        var disposition = client.ResponseHeaders["Content-Disposition"];
        if (disposition != null)
        {
            var cd = new ContentDisposition(disposition);
            if (!cd.Inline && !string.IsNullOrEmpty(cd.FileName))
            {
                using (var outputStream = File.OpenWrite(cd.FileName))
                {
                    stream.CopyTo(outputStream);
                }
            }
        }
        else
        {
            // The web server didn't send a Content-Disposition response header
            // so we have absolutely no means of determining the filename
            // you will have to use some default value here if you want to store it
        }
    }
}
于 2012-12-27T11:26:04.537 回答