10. 添加下载和响应的代码:
//使用指定的方法开始下载指定的URI。返回的任务生成
//HTTP响应文本。可以使用GetStatusCode()和GetReasonPrase()读取状态代码和原因。
task<wstring> HttpRequest::DownloadAsync(PCWSTR httpMethod, PCWSTR uri, cancellation_token cancellationToken,
PCWSTR contentType, IStream* postStream, uint64 postStreamSizeToSend)
{
// Create an IXMLHTTPRequest2 object.
ComPtr<IXMLHTTPRequest2> xhr;
CheckHResult(CoCreateInstance(CLSID_XmlHttpRequest, nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&xhr)));
// Create callback.
auto stringCallback = Make<HttpRequestStringCallback>(xhr.Get(), cancellationToken);
CheckHResult(stringCallback ? S_OK : E_OUTOFMEMORY);
auto completionTask = create_task(stringCallback->GetCompletionEvent());
// Create a request.
CheckHResult(xhr->Open(httpMethod, uri, stringCallback.Get(), nullptr, nullptr, nullptr, nullptr));
if (postStream != nullptr && contentType != nullptr)
{
CheckHResult(xhr->SetRequestHeader(L"Content-Type", contentType));
}
// Send the request.
CheckHResult(xhr->Send(postStream, postStreamSizeToSend));
// Return a task that completes when the HTTP operation completes.
// We pass the callback to the continuation because the lifetime of the
// callback must exceed the operation to ensure that cancellation
// works correctly.
return completionTask.then([this, stringCallback](tuple<HRESULT, wstring> resultTuple)
{
// If the GET operation failed, throw an Exception.
CheckHResult(std::get<0>(resultTuple));
statusCode = stringCallback->GetStatusCode();
reasonPhrase = stringCallback->GetReasonPhrase();
return std::get<1>(resultTuple);
});
}
11. 添加在指定的URI上启动HTTP GET代码:
//在指定的URI上启动HTTP GET。返回的任务在整个响应完成后完成
//并且该任务生成HTTP响应文本。状态代码和原因
//可以使用GetStatusCode()和GetReasonPrase()读取。
task<wstring> HttpRequest::GetAsync(Uri^ uri, cancellation_token cancellationToken)
{
return DownloadAsync(L"GET",
uri->AbsoluteUri->Data(),
cancellationToken,
nullptr,
nullptr,
0);
}
void HttpRequest::CreateMemoryStream(IStream **stream)
{
auto randomAccessStream = ref new Windows::Storage::Streams::InMemoryRandomAccessStream();
CheckHResult(CreateStreamOverRandomAccessStream(randomAccessStream, IID_PPV_ARGS(stream)));
}
12. 添加启动POST的代码:
//使用字符串体在指定的URI上启动HTTP POST。返回的任务生成
//HTTP响应文本。可以使用GetStatusCode()和GetReasonPrase()读取状态代码和原因。
task<wstring> HttpRequest::PostAsync(Uri^ uri, const wstring& body, cancellation_token cancellationToken)
{
int length = 0;
ComPtr<IStream> postStream;
CreateMemoryStream(&postStream);
if (body.length() > 0)
{
// Get the required buffer size.
int size = WideCharToMultiByte(CP_UTF8, // UTF-8
0, // Conversion type
body.c_str(), // Unicode string to convert
static_cast<int>(body.length()), // Size
nullptr, // Output buffer
0, // Output buffer size
nullptr,
nullptr);
CheckHResult((size != 0) ? S_OK : HRESULT_FROM_WIN32(GetLastError()));
std::unique_ptr<char[]> tempData(new char[size]);
length = WideCharToMultiByte(CP_UTF8, // UTF-8
0, // Conversion type
body.c_str(), // Unicode string to convert
static_cast<int>(body.length()), // Size
tempData.get(), // Output buffer
size, // Output buffer size
nullptr,
nullptr);
CheckHResult((length != 0) ? S_OK : HRESULT_FROM_WIN32(GetLastError()));
CheckHResult(postStream->Write(tempData.get(), length, nullptr));
}
return DownloadAsync(L"POST",
uri->AbsoluteUri->Data(),
cancellationToken,
L"text/plain;charset=utf-8",
postStream.Get(),
length);
}
13. 添加流媒体启动POST的函数:
//使用流媒体在指定的URI上启动HTTP POST。返回的任务生成
//HTTP响应文本。可以使用GetStatusCode()和GetReasonPrase()读取状态代码和原因。
task<wstring> HttpRequest::PostAsync(Uri^ uri, PCWSTR contentType, IStream* postStream,
uint64 postStreamSizeToSend, cancellation_token cancellationToken)
{
return DownloadAsync(L"POST",
uri->AbsoluteUri->Data(),
cancellationToken,
contentType,
postStream,
postStreamSizeToSend);
}
14. 添加发送请求的函数代码:
//发送请求,但不返回响应。相反,让调用者使用ReadAsync()读取它。
task<void> HttpRequest::SendAsync(const wstring& httpMethod, Uri^ uri, cancellation_token cancellationToken)
{
// Create an IXMLHTTPRequest2 object.
ComPtr<IXMLHTTPRequest2> xhr;
CheckHResult(CoCreateInstance(CLSID_XmlHttpRequest, nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&xhr)));
// Create callback.
buffersCallback = Make<Web::Details::HttpRequestBuffersCallback>(xhr.Get(), cancellationToken);
CheckHResult(buffersCallback ? S_OK : E_OUTOFMEMORY);
ComPtr<IXMLHTTPRequest2Callback> xhrCallback;
CheckHResult(buffersCallback.As(&xhrCallback));
// Open and send the request.
CheckHResult(xhr->Open(httpMethod.c_str(),
uri->AbsoluteUri->Data(),
xhrCallback.Get(),
nullptr,
nullptr,
nullptr,
nullptr));
responseComplete = false;
CheckHResult(xhr->Send(nullptr, 0));
// Return a task that completes when the HTTP operation completes.
// Since buffersCallback holds a reference on the callback, the lifetime of the callback will exceed
// the operation and ensure that cancellation works correctly.
return buffersCallback->CreateDataTask().then([this]()
{
CheckHResult(buffersCallback->GetError());
statusCode = buffersCallback->GetStatusCode();
reasonPhrase = buffersCallback->GetReasonPhrase();
});
}
15. 添加同步读的代码:
//从HTTP响应中读取一块数据,直到指定长度或到达末尾
//并将该值存储在提供的缓冲区中。这对于大内容是有用的,
//从而能够流式传输结果。
task<void> HttpRequest::ReadAsync(Windows::Storage::Streams::IBuffer^ readBuffer, unsigned int offsetInBuffer,
unsigned int requestedBytesToRead)
{
if (offsetInBuffer + requestedBytesToRead > readBuffer->Capacity)
{
throw ref new InvalidArgumentException();
}
// Return a task that completes when a read completes.
// We pass the callback to the continuation because the lifetime of the
// callback must exceed the operation to ensure that cancellation
// works correctly.
return buffersCallback->CreateDataTask().then([this, readBuffer, offsetInBuffer, requestedBytesToRead]()
{
CheckHResult(buffersCallback->GetError());
// Get a pointer to the location to copy data into.
ComPtr<IBufferByteAccess> bufferByteAccess;
CheckHResult(reinterpret_cast<IUnknown*>(readBuffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess)));
byte* outputBuffer; // Returned internal pointer, do not free this value.
CheckHResult(bufferByteAccess->Buffer(&outputBuffer));
// Copy bytes from the sequential stream into the buffer provided until
// we reach the end of one or the other.
readBuffer->Length = buffersCallback->ReadData(outputBuffer + offsetInBuffer, requestedBytesToRead);
if (buffersCallback->IsResponseReceived() && (readBuffer->Length < requestedBytesToRead))
{
responseComplete = true;
}
});
}
注意: 在 HttpRequest.cpp 中添加的代码包括7~15。