我希望能够控制在使用HttpClient或WebRequest发送Web请求时如何排序标头。
使用HttpClient时,总是在末尾添加主机和连接,并对其他标头进行排序,以便将它们添加到Headers集合中。
WebRequest将主机添加到标题的末尾。
我知道标题的顺序与网络服务器无关,但是,id喜欢以特定的方式对它们进行排序,因为订单将在服务器端以编程方式进行checekd。
有办法做到这一点吗?
答案 0 :(得分:0)
这是我的临时解决方法:
创建本地代理并通过它传递HttpClient请求。在代理内部,我按照我的要求重新排序标题。
我使用的本地代理是开源C#Titanium Web Proxy,它可以正常工作。它支持.NET Standard 2.0,因此它是跨平台的。
以下是测试代理设置和使用代理的客户端的代码示例。您必须自己实现事件处理程序。
<强>客户端强>:
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace TestClient
{
class Program
{
static void Main(string[] args)
{
var handler = new HttpClientHandler
{
Proxy = new WebProxy($"http://localhost:8000", false),
UseProxy = true,
};
var client = new System.Net.Http.HttpClient(handler);
var t = Task.Run(() => GetDataAsync(client, "http://google.com/"));
t.Wait();
var result = t.Result;
}
static async Task<string> GetDataAsync(System.Net.Http.HttpClient client, string path)
{
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return null;
}
}
}
}
代理服务器设置:
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models;
namespace ClassLibrary6
{
public class ProxySetup
{
public ProxySetup()
{
var proxyServer = new ProxyServer();
//locally trust root certificate used by this proxy
proxyServer.TrustRootCertificate = true;
//optionally set the Certificate Engine
//Under Mono only BouncyCastle will be supported
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
proxyServer.BeforeRequest += OnRequest;
proxyServer.BeforeResponse += OnResponse;
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
{
//Exclude HTTPS addresses you don't want to proxy
//Useful for clients that use certificate pinning
//for example dropbox.com
// ExcludedHttpsHostNameRegex = new List<string>() { "google.com", "dropbox.com" }
//Use self-issued generic certificate on all HTTPS requests
//Optimizes performance by not creating a certificate for each HTTPS-enabled domain
//Useful when certificate trust is not required by proxy clients
// GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
};
//An explicit endpoint is where the client knows about the existence of a proxy
//So client sends request in a proxy friendly manner
proxyServer.AddEndPoint(explicitEndPoint);
proxyServer.Start();
//Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy)
//A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS
//to send data to this endPoint
var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true)
{
//Generic Certificate hostname to use
//when SNI is disabled by client
GenericCertificateName = "google.com"
};
proxyServer.AddEndPoint(transparentEndPoint);
//proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
//proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
foreach (var endPoint in proxyServer.ProxyEndPoints)
Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
//Only explicit proxies can be set as system proxy!
//proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
//proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
//wait here (You can use something else as a wait function, I am using this as a demo)
Console.Read();
//Unsubscribe & Quit
proxyServer.BeforeRequest -= OnRequest;
proxyServer.BeforeResponse -= OnResponse;
proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;
proxyServer.Stop();
}
public async Task OnRequest(object sender, SessionEventArgs e)
{
e.WebSession.Request.RequestHeaders.AddHeader("Ab", "Moo");
var headers = e.WebSession.Request.RequestHeaders.GetAllHeaders();
var ordered = headers.OrderBy(x => x.Name);
e.WebSession.Request.RequestHeaders.Clear();
foreach (var httpHeader in ordered)
{
e.WebSession.Request.RequestHeaders.AddHeader(httpHeader);
}
}
public async Task OnResponse(object sender, SessionEventArgs e)
{
}
public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{
return null;
}
public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
{
return null;
}
}
}