
BEGIN_INTERFACE_PART(HttpNegotiateObj, IHttpNegotiate)
STDMETHOD_(HRESULT, BeginningTransaction)(LPCWSTR szUrl,
LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
STDMETHOD_(HRESULT, OnResponse)(DWORD dwResponseCode,
LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR*
pszAdditionalRequestHeaders)
END_INTERFACE_PART(HttpNegotiateObj)
3.
使用 MFC 的 BEGIN_INTERFACE_MAP 宏将 IHttpNegotiate 添加为一个 QI-able 接口。这应该位于该类的 .cpp 文件中。
BEGIN_INTERFACE_MAP(NegotiateCallback, CCmdTarget)
INTERFACE_PART(NegotiateCallback, IID_INegotiateCallback, Dispatch)
INTERFACE_PART(NegotiateCallback, IID_IHttpNegotiate, HttpNegotiateObj)
END_INTERFACE_MAP()
4.
提供 IHttpNegotiate 方法的实现,以便添加标头或检查响应标头。下面的代码会向传出事务添加一个 X-Custom-App HTTP 标头。请注意,您要负责在每个自定义标头的结尾插入一个 CR/LF(回车符/换行符);否则,您的自定义标头则会省略后面紧跟的标头,从而损坏您的 HTTP 事务。另外,还要确保使用 CoTaskMemAlloc() 来代替 C 运行库内存管理函数,以便 URLMON 可以通过调用 CoTaskMemFree() 来释放您的数据。
STDMETHODIMP NegotiateCallback::XHttpNegotiateObj::BeginningTransaction(LPCWSTR
szUrl, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR
*pszAdditionalHeaders) {
LPWSTR pszHeader = (LPWSTR)CoTaskMemAlloc(74)
memcpy((void*)pszHeader, (void*)L"X-Custom-App: Version
1.1.3748.9\r\n", 74)
*pszAdditionalHeaders=pszHeader
return S_OK
}
5.
创建一个新的 MFC 类,使其成为 CAsyncMonikerFile 的子类。我们将此类称为 CFetchData。
6.
重写 CAsyncMonikerFile 的 Open() 方法。此方法负责创建 MFC 用于接收下载状态事件的 IBindStatusCallback 实现。您需要使用一个指向 NegotiateCallback 的 IUnknown 的指针自己创建此回调,从而使得 MFC 的 IBindStatusCallback 实现和您的 IHttpNegotiate 实现能够得以聚合。聚合是一个 COM 技术,它能够使用一个类的功能来扩展另一个类。在此实例中,这就表示 URLMON 为 IHttpNegotiate 在 MFC 的 IBindStatusCallback 上执行的所有查询都将委托给您的 IHttpNegotiate 实现。
BOOL CFetchData::Open(LPCTSTR lpszURL, CFileException* pError) {
nc = new NegotiateCallback()
LPDISPATCH pNegCallDisp = nc->GetIDispatch(FALSE)
// I borrowed this from oleasmon.cpp.
IPTR(IBindHost) pBindHost(CreateBindHost(), FALSE)
IPTR(IBindCtx) pBindCtx(CreateBindContext(pError), FALSE)
if (pError &&(pError->m_cause != CFileException::none))
return FALSE
// Instantiate our NegotiateCallback object, and aggregate with the
// IBindStatusCallback supplied by MFC.
IPTR(IUnknown) pBSCUnk(CreateBindStatusCallback(pNegCallDisp), FALSE)
IPTR(IBindStatusCallback) pBSC
pBSCUnk->AddRef()
pBSC.QueryInterface(pBSCUnk)
return Attach(lpszURL, pBindHost, pBSC, pBindCtx, pError)
}
7.
为了在数据下载后接收数据,请在 CAsyncMonikerFile 上实现 IBindStatusCallback 方法。CAsyncMonikerFile 已经实现了此接口,因此您只需提供重写。
4种为HttpClient添加默认请求头的方式。下面详细的介绍;第一种方式
直接在创建的HttpClient对象的DefaultRequestHeaders集合中添加报头。
class Program
{undefined
static Task Main()=>SendAsync1()
private static async Task SendAsync1()
{undefined
var httpClient = new HttpClient()
AddDefaultHeaders(httpClient)
await httpClient.GetStringAsync("http://localhost:5000/")
}
private static void AddDefaultHeaders(HttpClient httpClient)
{undefined
httpClient.DefaultRequestHeaders.Add("x-www-foo", "123")
httpClient.DefaultRequestHeaders.Add("x-www-bar", "456")
httpClient.DefaultRequestHeaders.Add("x-www-baz", "789")
}
}
第二种方式
对于.NET Core应用来说,我们更推荐的做法是采用依赖注入的方式,利用IHttpClientFactory来创建HttpClient对象,那么我们在进行相关服务注册的时候就可以设置默认请求报头。
class Program
{undefined
static Task Main()=>SendAsync2()
private static async Task SendAsync2()
{undefined
var services = new ServiceCollection()
services.AddHttpClient("", AddDefaultHeaders)
var httpClient = services
.BuildServiceProvider()
.GetRequiredService()
.CreateClient()
await httpClient.GetStringAsync("http://localhost:5000/")
}
private static void AddDefaultHeaders(HttpClient httpClient)
{undefined
httpClient.DefaultRequestHeaders.Add("x-www-foo", "123")
httpClient.DefaultRequestHeaders.Add("x-www-bar", "456")
httpClient.DefaultRequestHeaders.Add("x-www-baz", "789")
}
}
第三种方式
由于HttpClient在发送请求的时候会利用DiagnosticSource对象发送相应的诊断事件,并且将作为请求的HttpRequestMessage对象作为请求事件内容负载。我们可以订阅该事件,在请求被发送之前将其拦截下来,并添加相应的请求头即可。
class Program
{undefined
static Task Main()=>SendAsync3()
private static async Task SendAsync3()
{undefined
Func requestAccessor = null
DiagnosticListener.AllListeners.Subscribe(listener =>
{undefined
if (listener.Name == "HttpHandlerDiagnosticListener")
{undefined
listener.Subscribe(kv =>
{undefined
if (kv.Key == "System.Net.Http.HttpRequestOut.Start")
{undefined
requestAccessor ??= BuildRequestAccessor(kv.Value.GetType())
var request = requestAccessor(kv.Value)
AddDefaultHeaders(request)
}
})
}
})
var httpClient = new HttpClient()
await httpClient.GetStringAsync("http://localhost:5000/")
static Func BuildRequestAccessor(Type payloadType)
{undefined
var property = payloadType.GetProperty("Request", BindingFlags.Instance | BindingFlags.Public)
var payload = Expression.Parameter(typeof(object))
var convertedPayload = Expression.Convert(payload, payloadType)
var getRequest = Expression.Call(convertedPayload, property.GetMethod)
var convert = Expression.Convert(getRequest, typeof(HttpRequestMessage))
return Expression.Lambda>(convert, payload).Compile()
}
}
private static void AddDefaultHeaders(HttpRequestMessage request)
{undefined
request.Headers.Add("x-www-foo", "123")
request.Headers.Add("x-www-bar", "456")
request.Headers.Add("x-www-baz", "789")
}
}
第四种方式
上面这种方式可以采用强类型编程方式,具体的代码如下。
class Program
{undefined
static Task Main()=>SendAsync4()
private static async Task SendAsync4()
{undefined
DiagnosticListener.AllListeners.Subscribe(listener =>
{undefined
if (listener.Name == "HttpHandlerDiagnosticListener")
{undefined
listener.SubscribeWithAdapter(new HttpClientListener())
}
})
var httpClient = new HttpClient()
await httpClient.GetStringAsync("http://localhost:5000/")
}
private sealed class HttpClientListener
{undefined
[DiagnosticName("System.Net.Http.HttpRequestOut.Start")]
public void OnSend(HttpRequestMessage request) =>AddDefaultHeaders(request)
//Must subscribute the System.Net.Http.HttpRequestOut event.
[DiagnosticName("System.Net.Http.HttpRequestOut")]
public void OnSend() { }
}
private static void AddDefaultHeaders(HttpRequestMessage request)
{undefined
request.Headers.Add("x-www-foo", "123")
request.Headers.Add("x-www-bar", "456")
request.Headers.Add("x-www-baz", "789")
}
}
场景是这样的,第三方页面访问需要鉴权,所以需要在HTTP头中增加鉴权的属性和内容发送给第三方网页。我试过用response.addHeader("Authorization","xxxxxxxxx")方法,但发送的请求还是不带Authorization属性,还请大牛们不吝指教。
你这个问题实际上是服务器访问第三方鉴权系统,这个访问过程和客户端没关系的
和response,request都没关系
是要在服务器端模拟http请求,在这个请求里面增加自定义header
用HttpClient很容易
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)