如何使用 Windows.Web.Http 连接到 HTTP 服务器 (HTML)

[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]

使用 Windows.Web.Http 命名空间中的 Windows.Web.Http.HttpClient 类向 Web 服务发送 GET 请求并检索响应。

[立即获取 HTTPClient 示例。]

Windows.Web.Http 命名空间中的类可为现代 HTTP 客户端应用提供编程接口。Windows.Web.Http 命名空间和相关的 Windows.Web.Http.HeadersWindows.Web.Http.Filters 命名空间提供的 HTTP 客户端组件,允许用户通过 HTTP 使用现代的 Web 服务发出 HTTP 请求和接收 HTTP 响应。

Windows 8.1 引入了 Windows.Web.Http,即,用于连接到 HTTP 和代表性状态传输 (REST) Web 服务的 Windows 应用的 Windows 运行时命名空间。 这个新 API 在所有支持语言中提供了所有功能支持,并替代了最初为 Windows 8 发布的 HTTP API。

这个新的 API 替换了三个不同的 API,这些 API 具有以前 Windows 8 中每种语言投影所需的不同的功能。

对于基本的请求操作,新 API 有一个简单的接口来处理最常见的任务,并为身份验证 (AUTH) 提供了适用于大多数方案的合理的默认设置。对于较为复杂的 HTTP 操作,包括更多的功能。

  • 执行常见操作(DELETEGETPUTPOST)的方法

  • 支持常见的身份验证设置和模式

  • 访问有关传输的安全套接字层 (SSL) 详细信息

  • 在高级应用中包含自定义筛选器的功能

  • 获取、设置和删除 Cookie 的功能

  • 异步方法上提供的 HTTP 请求进度信息

Windows.Web.Http.HttpClient 类用于通过 HTTP 发送和接收基本请求。它提供了一个用于从 URI 所标识的资源发送 HTTP 请求和接收 HTTP 响应的主类。该类可用来向 Web 服务发送 GET、PUT、POST、DELETE 以及其他请求。上述每种请求都作为异步操作进行发送。

Windows.Web.Http.HttpRequestMessage 类用于声明由 Windows.Web.Http.HttpClient 发送的 HTTP 请求消息。Windows.Web.Http.HttpResponseMessage 类用于声明从 HTTP 请求接收到的 HTTP 响应消息。HTTP 消息由 IETF 在 RFC 2616 中进行定义。

Windows.Web.Http 命名空间提供很多不同的类,这些类用于声明与 HTTP 请求或 HTTP 响应相关联的 HTTP 内容(HTTP 实体正文和包含 Cookie 的内容标题)。 这些不同的类允许内容使用缓冲区、字符串和流,以及使用 application/x-www-form-urlencoded MIME 类型、multipart/* MIME 类型和 multipart/form-data MIME 类型对名称/值数据进行编码。 也可以定义自定义内容。

在此示例中,HttpStringContent 类作为字符串用于声明 HTTP 响应。

Windows.Web.Http.Headers 命名空间支持创建 HTTP 标头和 Cookie,然后再将生成的 HTTP 标头和 Cookie 作为属性与 HttpRequestMessageHttpResponseMessage 对象相关联。

先决条件

在本主题中,以下示例都来自 JavaScript 和 HTML。你必须对 RFC 2616 中详细描述的 HTTP 请求有基本的了解。

它还可能使用 WinJS.xhrXMLHttpRequest,在使用 JavaScript 和 HTML 的应用中发出 HTTP 请求。有关详细信息,请参阅连接到 Web 服务(使用 JavaScript 的 Windows 运行时应用)

说明

步骤 1: 创建新项目

  1. 打开 Microsoft Visual Studio 2013,然后从“文件”菜单中选择“新建项目”****。
  2. 在模板列表中,选择 JavaScript
  3. 在该部分下,选择 Store apps
  4. 在该部分下,选择 Universal AppsWindows appsWindows Phone apps(取决于你面向的平台),然后选择“空白应用程序”。
  5. 将该应用程序命名为 HttpClientGet,然后单击“确定”****。

步骤 2: 设置启用网络访问的功能

你需要为你的应用设置网络功能,以启用对专用的家庭或工作网络以及 Internet 的访问。你需要为该应用启用网络功能,因为客户端正连接到 Web 服务。

对于使用 Windows.Web.Http.HttpClient 连接到另一台计算机上 Web 服务的应用,该应用将需要设置网络功能集。如果应用需要作为客户端连接到 Internet 上的 Web 服务,则需要设置“Internet (客户端)”功能。如果应用需要作为客户端连接到家庭网络或工作网络上的 Web 服务,则需要设置“专用网络(客户端和服务器)”****功能。

注意  在 Windows Phone 上,只存在“Internet (客户端和服务器)”这一种网络功能,该功能支持对该应用的所有网络访问。

 

如果 Web 服务与应用运行于同一台计算机上,则需要设置环回访问。在 Visual Studio 2013 中开发和运行的应用将自动注册为已免除环回限制。有关详细信息,请参阅如何启用环回和调试网络隔离

有关网络访问的更多信息,请参阅如何配置网络功能

如果应用要访问位于 Internet 或者专用或工作网络上的 Web 服务,则需要按照以下步骤在部署之前为应用设置网络功能。

  1. 使用 Visual Studio 2013 打开 package.appxmanifest 文件。

  2. 选择****“功能”选项卡。

  3. 要构建示例的 Windows 版本,请选择“Internet (客户端)”和“专用网络 (客户端和服务器)”****功能。

    要构建示例的 Windows Phone 版本,请选择“Internet (客户端和服务器)”功能。

  4. 保存并关闭清单文件。

步骤 3: 添加 HTML UI

  • 在本节中,我们将在 HTML 中定义应用的布局,以指定应用中每个对象的大概大小和位置。 通过添加显示数据的控件和内容,我们已经完成了应用的用户界面。

    此示例使用了简单的 HTML UI 元素,包括:

    • 用于文本标签的带有 class 的控件、用于输入 URI 地址的输入字段,以及用于启动异步请求的 button

    • 带有 class、文本标签和文本字段的控件,用来显示当前状态。状态和错误消息将显示在这里。该控件还包括 class,从 Web 服务接收的输出将显示在这里。在此示例中,HTTP GET 操作的结果会以包含 HTML 标记的纯文本显示。

    打开 js 文件夹和打开现有的 default.js 文件并将以下 UI 元素添加到该文件中。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>HttpClientGet</title>
    
        <!-- WinJS references - Windows -->
        <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
        <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
        <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
    
        <!-- WinJS references - Phone -->
        <link href="/css/ui-themed.css" rel="stylesheet" />
        <script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script>
        <script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script>
    
        <!-- HttpClientGet references -->
        <link href="/css/default.css" rel="stylesheet" />
        <script src="/js/default.js"></script>
        <script src="/js/mainpage.js"></script>
    </head>
    
    <body>
        <div data-win-control="SampleInput">
            <p> Download the contents of a page and display it. </p>
            <p class="clear">
                <label for="inputAddress">URI Address:</label>
                <input type="text" id="inputAddress" value="https://www.contoso.com" />
            </p>
            <p>
                <button id="startButton">Start</button>
            </p>
        </div>
        <div data-win-control="SampleOutput">
            <p class="clear">
                <label for="statusText">Status:</label>
                <input type="text" id="statusText" value="" />
            </p>
            <textarea id="outputView"></textarea>
        </div>
    </body>
    </html>
    

步骤 4: 创建 HttpClient

  • 首先创建 Windows.Web.Http.HttpClient 对象并添加用户代理标头。

    默认情况下,HttpClient 对象不会将用户代理标头随 HTTP 请求一起发送到 Web 服务。某些 HTTP 服务器(包括某些 Microsoft Web 服务器)要求从客户端发送的 HTTP 请求附带用户代理标头。如果标头不存在,则 HTTP 服务器返回错误。在 Windows.Web.Http.Headers 命名空间中使用类时,需要添加用户代理标头。我们将该标头添加到 HttpClient.DefaultRequestHeaders 属性以避免这些错误。

    打开 js 文件夹并打开一个新的 mainpage.js 文件,将以下代码添加到该文件中。

    (function () {
        "use strict";
    
        var httpClient;
        var httpPromise;
    
        var page = WinJS.UI.Pages.define("/html/mainpage.html", {
            ready: function (element, options) {
                document.getElementById("startButton").addEventListener("click", start, false);
    
                httpClient = new Windows.Web.Http.HttpClient();
    
                // Add a user-agent header
                headers = httpClient.defaultRequestHeaders;
    
                // UserAgent is a HttpProductInfoHeaderValueCollection
                // A collection of HttpProductInfoHeaderValue items
    
                // The safe way to check a header value from the user is the TryParseAdd method
                // Since we know this header is okay, we use ParseAdd with will throw an exception
                // with a bad value 
    
                headers.userAgent.parseAdd("ie");
                headers.userAgent.parseAdd("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
            }
        });
    })();
    

    打开 js 文件夹并打开 default.js 文件,将以下代码添加到该文件中。

    (// For an introduction to the Blank template, see the following documentation:
    // https://go.microsoft.com/fwlink/p/?LinkID=232509
    (function () {
        "use strict";
    
        var app = WinJS.Application;
        var activation = Windows.ApplicationModel.Activation;
    
        app.onactivated = function (args) {
            if (args.detail.kind === activation.ActivationKind.launch) {
                if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                    startButton.onclick = start;
    
                } else {
                    startButton.onclick = start;
                }
                args.setPromise(WinJS.UI.processAll());
            }
        };
    
        app.oncheckpoint = function (args) {
            // This application is about to be suspended. Save any state
            // that needs to persist across suspensions here. You might use the
            // WinJS.Application.sessionState object, which is automatically
            // saved and restored across suspension. If you need to complete an
            // asynchronous operation before your application is suspended, call
            // args.setPromise().
        };
    
        app.start();
    })();
    

步骤 5: 发送 GET 请求并接收响应

  • 当单击“开始”按钮时,首先验证在 inputAddress 中指定的 URI 是否有效。然后使用该 URI 发送 GET 请求并等待接收来自 HTTP 服务器的响应。

    在单击“开始”Button 的处理程序后,大部分工作已经完成。当单击该按钮时,将更新 statusTextoutputView UI 元素中的文本。首先检查输入 URI 地址,确保用户传递了有效的 URI 地址。如果我们通过用户获得有效的 URI,则应用将 HTTP GET 请求发送到指定的 URI 并等待 HTTP 响应。如果发生错误或异常,结果会显示在 statusText UI 元素中。如果没有错误发生,则来自该 Web 服务的响应将显示在 outputView UI 元素中。

    当统一资源标识符 (URI) 的无效字符串传递到 Windows.Foundation.Uri 对象的构造函数时,会引发异常。

    使用 JavaScript 时,没有可用于试用字符串和将其解析到 URI 的方法。若要在这种情况下捕获此异常,请在构造 URI 构造的位置在代码周围使用 try/catch 块。

    如果这些架构是仅受 Windows.Web.Http.HttpClient 支持的架构,则该示例还应该检查 URI 中的 HTTP 方案是 HTTP 还是 HTTPS。

    在 JavaScript 中使用 thendone 关键字时,发送 GET 请求并异步检索响应的代码与我们用于同步完成该操作的代码相似。

    随时可能由网络错误(例如连接中断、连接失败和 HTTP 服务器失败)引发异常。这些错误将引发异常。如果应用不处理异常,它可能导致整个应用在运行时终止。 当你调用大部分异步网络方法时,必须编写代码以处理异常。有时,如果发生异常,可以重试网络方法来尝试解决问题。其他时候,应用可能需要计划使用之前的缓存数据在没有网络连接的情况下继续工作。有关处理网络异常的详细信息,请参阅处理网络应用中的异常

    如果 Web 服务器为该请求返回 HTTP 错误状态代码(HttpResponse.StatusCode 不在 Successful 范围 (200-299) 内),则 HttpResponse.EnsureSuccessStatusCode 方法将引发异常。如果发生错误,则对任何异常使用 try/catch 块,并打印出 statusText UI 元素中的异常消息。

    HttpResponse.Content 属性声明 HTTP 响应的内容。HttpClient.GetAsync(Uri) 方法将 HTTP 内容作为异步操作读取到字符串中。 为了方便显示,我们将所返回的 HTML 文本中的所有 <br> 标记都替换成了新行。如果该方法成功,我们将在 statusText UI 元素中和由 outputView UI 元素中的 Web 服务返回的 HttpResponse.Content 中显示 HttpResponse.StatusCode

    打开 js 文件夹,并将以下代码添加到 mainpage.js 文件中。

        function start()
        {
    
            var response = new Windows.Web.Http.HttpResponseMessage();
    
            var statusText = document.getElementById("statusText");
            var outputView = document.getElementById("outputView");
    
            // The value of 'inputAddress' is set by the user 
            // and is therefore untrusted input. 
            // If we can't create a valid absolute URI, 
            // We notify the user about the incorrect input.
    
            statusText.Text = "Testing URI is valid.";
    
            var uriString = document.getElementById("inputAddress").value.trim();
            if (!uriString) {
                return;
            }
    
            var resourceUri;
            try {
               resourceUri = new Windows.Foundation.Uri(uriString);
            }
            catch (Exception) {
                statusText.Text = "Invalid URI, please re-enter a valid URI.";
                return;
            }
    
            if (resourceUri.schemeName != "http" && resourceUri.schemeName != "https") {
                statusText.Text = "Only 'http' and 'https' schemes supported. Please re-enter URI";
                return;
            }
    
            var responseBodyAsText="";
            outputView.Text = "";
            statusText.Text = "Waiting for response ...";
    
            httpPromise = httpClient.getAsync(resourceUri).then(function (response) {
                outputStatus = response.statusCode + " " + response.reasonPhrase;
    
                response.EnsureSuccessStatusCode();
    
                response.content.readAsStringAsync().then(function (responseBodyAsText) {
                // Format the HTTP response to display better
                responseBodyAsText = responseBodyAsText.replace(/<br>/g, "\r\n");
                outputView.value = responseBodyAsText;
                return response;
            });
        )};
    
        httpPromise.done(function (response) {
            statusText.value = response.StatusCode + " " + response.ReasonPhrase + "\r\n";
        }, onError);
    
        function onError(error) {
            statusText.value = "Error = " + error.number + "  Message: " + error.message;
        }
    
    })();
    

    Windows.Web.Http.HttpClient 使用 WinInet 发送 HTTP 和 Web 服务请求并接收响应。由 WinInet 用于 HTTP 连接操作的默认超时值为 60 秒。如果 HTTP 服务器或 Web 服务临时关闭或被防火墙阻止并且服务器不能响应 Windows.Web.Http.HttpClient 请求,则 WinInet 在返回一个导致应用引发异常的错误之前,默认等待 60 秒。如果对 HTTP 服务器名称的名称查询返回该名称的多个 IP 地址,则 WinInet 为该网站尝试许多其他 IP 地址,并且每次尝试在失败前都默认为 60 秒的超时时间。由 WinInet 返回错误或引发异常之前,发出 HTTP 或 Web 服务请求的应用可能为尝试多个 IP 地址而等待数分钟。此行为可能会使用户以为应用已停止工作。建立连接后,WinInet 用于发送和接收操作的默认超时为 30 秒。

    若要使应用的响应速度更快和最大程度地减少这些问题,可以通过对 Windows.Web.Http.HttpClient 操作设置较短的超时时间来增强应用,以便操作在超时(而不是使用默认的 WinInet 设置)后很快失败。有关如何设置超时的详细信息,请参阅使用 WinJS.xhr 或 HttpClient 设置超时值如何针对套接字操作设置超时

备注

在本主题中,我们已了解如何使用 Windows.Web.Http.HttpClient 类向 Web 服务发送 GET 请求以及如何使用 Windows.Web.Http.HttpResponseMessageWindows.Web.Http.Headers 命名空间中的相关类检索响应。

相关主题

其他资源

连接到 Web 服务

处理网络应用中的异常

如何配置网络功能

如何启用环回和调试网络隔离

使用 WinJS.xhr 或 HttpClient 设置超时值

参考

Windows.Foundation.Uri

Windows.Web.Http

Windows.Web.Http.Filters

Windows.Web.Http.Headers

示例

HttpClient 示例

Web 身份验证示例