【问题标题】:How to get Location header with WebClient after POST requestPOST请求后如何使用WebClient获取位置标头
【发布时间】:2018-02-14 11:40:11
【问题描述】:

在成功的 POST 请求之后,我需要使用 WebClient 来获取响应标头内的 url。

但是我在执行WebClient.UploadValues 后得到的标题是页面被重定向之后的标题。

使用浏览器(红色突出显示我需要的标题):

这段代码使用WebClient模拟与浏览器中相同的操作:

NameValueCollection formData = new NameValueCollection();
formData["username"] = user;
formData["password"] = password;

byte[] responseBytes = webClient.UploadValues(loginUrl, "POST", formData);
string response = Encoding.UTF8.GetString(responseBytes);

string allheaders = "";
for (int i = 0; i < webClient.ResponseHeaders.Count; i++)
{
    allheaders += Environment.NewLine + webClient.ResponseHeaders.GetKey(i) + " = " + webClient.ResponseHeaders.Get(i);                        
}
File.WriteAllText("headers_2.txt", "[HEADER_2] " + allheaders);

...结果 headers_2.txt 不包含 Location 标头(这些标头来自用户被重定向到的页面):

[HEADER_2] Pragma = 无缓存 Cache-Control = 无存储、无缓存、必须重新验证 日期 = 格林威治标准时间 2018 年 2 月 14 日星期三 10:58:10 过期 = 1981 年 11 月 19 日星期四 08:52:00 GMT P3P = fffff 设置 Cookie = sid=ffffff;路径=/,gameapi_console=0;到期=格林威治标准时间 2018 年 3 月 17 日星期六 10:58:10;最大年龄=2678400;路径=/,bptid=ffffff;路径=/ 服务器 = 阿帕奇 变化 = 接受编码,用户代理 访问控制允许来源 = * 内容类型 = 文本/html;字符集=UTF-8 传输编码 = 分块

如何使用 WebClient 获取 Location 标头?如果可以的话。

更新:

感谢 cmets。

我忘了展示我尝试过的内容。 所以我创建了自己的类,它继承自WebClient。我在想,如果我在UploadValuesCompleted 被触发的那一刻阅读标题 - 我将在自动重定向之前获得标题。不幸的是,由于未知原因,即使在我致电 webClient.UploadValues(loginUrl, "POST", formData) 之后,该事件也从未被触发。

class FAWebClient : WebClient
{
    public event Action<string> OnLocationHeaderFound;

    public FAWebClient(Action<string> pOnLocationHeaderFound = null) :base()
    {
        UploadValuesCompleted += OnUploadValuesCompleted;

        if(pOnLocationHeaderFound != null)
            this.OnLocationHeaderFound += pOnLocationHeaderFound;
    }

    protected override void OnUploadValuesCompleted(object sender, UploadValuesCompletedEventArgs e) 
    {
        if (this.OnLocationHeaderFound != null)
        {
            for (int i = 0; i < this.ResponseHeaders.Count; i++)
            {
                System.Diagnostics.Debug.WriteLine(this.ResponseHeaders.GetKey(i) + " = " + this.ResponseHeaders.Get(i));

                if (this.ResponseHeaders.GetKey(i).ToLower() == "location")
                {
                    OnLocationHeaderFound(this.ResponseHeaders.Get(i));
                }
            }
        }

        base.OnUploadValuesCompleted(e);
    }
}

另外请注意,我使用 HttpClient 解决了这个问题,只需将 HttpClient.AllowAutoRedirect 设置为 false:

 var handler = new HttpClientHandler()
 {
      AllowAutoRedirect = false
 };

因此,我不得不对我的应用程序逻辑进行大量更改,但它确实有效。 但是,如果有人愿意提供解决方案或回答如何通过WebClient 实现这一目标,我将保持开放状态。

【问题讨论】:

  • 如果您需要对请求/响应进行更多控制,您应该考虑使用 WebRequest/WebResponse,它允许您设置 AllowAutoRedirect = false。 @mjwills 链接的一个问题是这样做的,其类派生自WebClient。请注意,并非所有服务器/html 页面都设置了 Location Header。有些只是使用刷新设置为 0 的 http-equiv 元标记或设置新位置的 javascript 创建重定向。发生这种情况时,HttpStatusCode 通常是 200(OK)而不是 302(找到)或 301(移动)或 303(重定向)。通常在 Web 窗体身份验证中。
  • 在您的自定义 WebClient 的 WebRequest 上设置 AllowAutoRedirect =false 是否有问题?您需要其他解决方案吗?您可以覆盖 GetWebRequest ,将 base.GetWebRequest(address) 转换为 HttpWebRequest 并将 AllowAutoRedirect 设置为 false
  • @GeorgeVovos 我将在下周检查是否可以按照您提到的那样在 WebClient 中设置 AllowAutoRedirect 并在此处发表评论。不,我不是在寻找其他解决方案 - 所以如果这真的有效,请随时创建答案。

标签: c# .net


【解决方案1】:

看来您已经知道解决方案了。
您所要做的就是配置 WebClient 以使用它。
假设您的服务器端代码如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace WebApplication12.Controllers
{
    public class HomeController : Controller
    {
        [HttpPost]
        public ActionResult Login(LoginModel credential)
        {
            //code
            Response.Headers.Add("IndexHeader","IndexHeaderValue");
            return RedirectToAction("About");
        }

        public ActionResult About()
        {
            Response.Headers.Add("AboutHeader", "AboutHeaderValue");
            return View();
        }
    }

    public class LoginModel
    {
        public string username { get; set; }
        public string password { get; set; }
    }
}

您可以像这样创建自定义 WebClient:

using System;
using System.Collections.Specialized;
using System.Net;

namespace ConsoleApp18
{
    public class NoRedirectWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            var temp = base.GetWebRequest(address) as HttpWebRequest;
            temp.AllowAutoRedirect = false;
            return temp;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MakeRequest(new WebClient());//Prints the AboutHeader
            Console.WriteLine();
            MakeRequest(new NoRedirectWebClient());//Prints the IndexHeader
            Console.ReadLine();
        }

        private static void MakeRequest(WebClient webClient)
        {
            var loginUrl = @"http://localhost:50900/Home/Login";
            NameValueCollection formData = new NameValueCollection();
            formData["username"] = "batman";
            formData["password"] = "1234";

            webClient.UploadValues(loginUrl, "POST", formData);

            string allheaders = "";
            for (int i = 0; i < webClient.ResponseHeaders.Count; i++)
                allheaders += Environment.NewLine + webClient.ResponseHeaders.GetKey(i) + " = " +
                              webClient.ResponseHeaders.Get(i);

            Console.WriteLine("******"+webClient.GetType().FullName+"*******");
            Console.Write(allheaders);
        }
    }
}

【讨论】:

  • @JerrySwitalski,这应该可以完成工作。如果不行请更新
  • 是的。谢谢
猜你喜欢
  • 1970-01-01
  • 2022-08-07
  • 2014-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 2011-09-25
  • 1970-01-01
相关资源
最近更新 更多