重新想象 Windows 8 Store Apps (61) - 通信: http, oauth

简介: 原文:重新想象 Windows 8 Store Apps (61) - 通信: http, oauth[源码下载] 重新想象 Windows 8 Store Apps (61) - 通信: http, oauth 作者:webabcd介绍重新想象 Windows 8 Store Apps 之 ...
原文: 重新想象 Windows 8 Store Apps (61) - 通信: http, oauth

[源码下载]


重新想象 Windows 8 Store Apps (61) - 通信: http, oauth



作者:webabcd


介绍
重新想象 Windows 8 Store Apps 之 通信

  • HttpClient 概述
  • http get string
  • http get stream
  • http post string
  • http post stream
  • OAuth 2.0 验证的客户端



示例
用于演示 http 通信的服务端
WebServer/HttpDemo.aspx.cs

/*
 * 用于响应 http 请求
 */

using System;
using System.IO;
using System.Threading;

namespace WebServer
{
    public partial class HttpDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // 停 3 秒,以方便测试 http 请求的取消
            Thread.Sleep(3000);

            var action = Request.QueryString["action"];

            switch (action)
            {
                case "getString": // 响应 http get string 
                    Response.Write("hello webabcd");
                    break;
                case "getStream": // 响应 http get stream 
                    Response.Write("hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd");
                    break;
                case "postString": // 响应 http post string 
                    Response.Write(string.Format("param1:{0}, param2:{1}, referrer:{2}", Request.Form["param1"], Request.Form["param2"], Request.UrlReferrer));
                    break;
                case "postStream": // 响应 http post stream 
                    using (StreamReader reader = new StreamReader(Request.InputStream))
                    {
                        string body = reader.ReadToEnd();
                        Response.Write(Server.HtmlEncode(body));
                    }
                    break;
                default:
                    break;
            }

            Response.End();
        }
    }
}

 

1、通过 HttpClient, HttpRequestMessage, HttpResponseMessage 实现 HTTP 通信
Communication/HTTP/Summary.xaml

<Page
    x:Class="XamlDemo.Communication.HTTP.Summary"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Communication.HTTP"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

            <Button Name="btnPost" Content="http post" Click="btnPost_Click_1" Margin="0 10 0 0" />

            <Button Name="btnCancel" Content="cancel" Click="btnCancel_Click_1" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

Communication/HTTP/Summary.xaml.cs

/*
 * 通过 HttpClient, HttpRequestMessage, HttpResponseMessage 实现 HTTP 通信
 * 
 * HttpClient - 用于发起 http 请求,以及接收 http 响应
 *     BaseAddress - 发送请求的 uri
 *     DefaultRequestHeaders - 默认的 http 请求头信息
 *     MaxResponseContentBufferSize - 读取响应内容时,所可以缓冲的最大字节数。默认值:64K
 *     Timeout - http 请求的超时时间
 *     CancelPendingRequests() - 取消该 HttpClient 对象所有挂起的 http 请求
 *     GetStringAsync(), GetStreamAsync(), GetByteArrayAsync(), GetAsync() - http get 数据
 *     PostAsync(), DeleteAsync(), PutAsync() - http post delete put 数据
 *         参数:HttpContent content - http 请求的数据(HttpContent 类型)
 *             继承自 HttpContent 的类有:StringContent, ByteArrayContent, StreamContent, FormUrlEncodedContent 等
 *         参数:HttpCompletionOption completionOption(HttpCompletionOption 枚举)
 *             ResponseContentRead - 获取到全部内容后再返回数据,默认值
 *             ResponseHeadersRead - 获取到头信息后就返回数据,用于流式获取
 * 
 * HttpRequestMessage - http 请求
 *     Method - http 方法
 *     RequestUri - 请求的 uri
 *     Version - http 版本,默认是 1.1
 *     Headers - http 的请求头信息
 *     Content - http 请求的内容(HttpContent 类型)
 *         继承自 HttpContent 的类有:StringContent, ByteArrayContent, StreamContent, FormUrlEncodedContent 等
 *         
 * HttpResponseMessage - http 响应
 *     RequestMessage - 对应的 HttpRequestMessage 对象
 *     Headers - http 的响应头信息
 *     Version - http 版本,默认是 1.1
 *     StatusCode - http 响应的状态码
 *     ReasonPhrase - http 响应的状态码所对应的短语
 *     IsSuccessStatusCode - http 响应的状态码是否是成功的值(200-299)
 *     EnsureSuccessStatusCode() - 当 IsSuccessStatusCode 为 false 时会抛出异常
 *     
 * 
 * 注:关于下载/上传的进度获取,请参见“后台任务”
 * 
 * 另:win8 metro 的 http 抓包可用 fiddler
 * 
 * 还有:
 * http 通信还可以通过如下方法实现
 * HttpWebRequest webRequest = WebRequest.Create(url);
 */

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace XamlDemo.Communication.HTTP
{
    public sealed partial class Summary : Page
    {
        private HttpClient _httpClient;

        public Summary()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 释放资源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }

        private async void btnPost_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();

            try
            {
                string url = "http://localhost:39629/HttpDemo.aspx?action=postString";
                // 创建一个 HttpRequestMessage 对象
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);

                // 需要 post 的数据
                var postData = new FormUrlEncodedContent(
                    new List<KeyValuePair<string, string>>
                    {
                        new KeyValuePair<string, string>("param1", "web"),
                        new KeyValuePair<string, string>("param2", "abcd")
                    }
                );

                // http 请求的数据
                request.Content = postData;
                // http 请求的头信息
                request.Headers.Referrer = new Uri("http://webabcd.cnblogs.com");

                // 请求 HttpRequestMessage 对象,并返回 HttpResponseMessage 数据
                HttpResponseMessage response = await _httpClient.SendAsync(request);

                // http 响应的状态码及其对应的短语
                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;

                // 以字符串的方式获取响应数据
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }

        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 请求
            _httpClient.CancelPendingRequests();
        }
    }
}


2、演示 http get string
Communication/HTTP/GetString.xaml.cs

/*
 * 演示 http get string
 */

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace XamlDemo.Communication.HTTP
{
    public sealed partial class GetString : Page
    {
        private HttpClient _httpClient;

        public GetString()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 释放资源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }

        private async void btnGetString_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();

            try
            {
                HttpResponseMessage response = await _httpClient.GetAsync(new Uri("http://localhost:39629/HttpDemo.aspx?action=getString"));

                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;

                // HttpContent.ReadAsStringAsync() - 以 string 方式获取响应数据
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式获取响应数据
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式获取响应数据
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
             catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }

        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 请求
            _httpClient.CancelPendingRequests();
        }
    }
}


3、演示 http get stream
Communication/HTTP/GetStream.xaml.cs

/*
 * 演示 http get stream
 */

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace XamlDemo.Communication.HTTP
{
    public sealed partial class GetStream : Page
    {
        private HttpClient _httpClient;

        public GetStream()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 释放资源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }

        private async void btnGetStream_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();

            try
            {
                // HttpCompletionOption.ResponseHeadersRead - 获取到头信息后就返回数据,用于流式获取
                HttpResponseMessage response = await _httpClient.GetAsync(
                    new Uri("http://localhost:39629/HttpDemo.aspx?action=getStream"), 
                    HttpCompletionOption.ResponseHeadersRead);

                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;

                // HttpContent.ReadAsStringAsync() - 以 string 方式获取响应数据
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式获取响应数据
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式获取响应数据
                using (Stream responseStream = await response.Content.ReadAsStreamAsync())
                {
                    byte[] buffer = new byte[32];
                    int read = 0;

                    while ((read = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        lblMsg.Text += "读取的字节数: " + read.ToString();
                        lblMsg.Text += Environment.NewLine;

                        IBuffer responseBuffer = CryptographicBuffer.CreateFromByteArray(buffer);
                        lblMsg.Text += CryptographicBuffer.EncodeToHexString(responseBuffer);
                        lblMsg.Text += Environment.NewLine;

                        buffer = new byte[32];
                    }
                }
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
             catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }

        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 请求
            _httpClient.CancelPendingRequests();
        }
    }
}


4、演示 http post string
Communication/HTTP/PostString.xaml.cs

/*
 * 演示 http post string
 */

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace XamlDemo.Communication.HTTP
{
    public sealed partial class PostString : Page
    {
        private HttpClient _httpClient;

        public PostString()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 释放资源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }

        private async void btnPostString_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();

            try
            {
                // 需要 post 的数据
                var postData = new FormUrlEncodedContent(
                    new List<KeyValuePair<string, string>>
                    {
                        new KeyValuePair<string, string>("param1", "web"),
                        new KeyValuePair<string, string>("param2", "abcd")
                    } 
                );

                HttpResponseMessage response = await _httpClient.PostAsync(
                    new Uri("http://localhost:39629/HttpDemo.aspx?action=postString"),
                    postData);

                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;

                // HttpContent.ReadAsStringAsync() - 以 string 方式获取响应数据
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式获取响应数据
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式获取响应数据
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }

        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 请求
            _httpClient.CancelPendingRequests();
        }
    }
}


5、演示 http post stream
Communication/HTTP/PostStream.xaml.cs

/*
 * 演示 http post stream
 */

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace XamlDemo.Communication.HTTP
{
    public sealed partial class PostStream : Page
    {
        private HttpClient _httpClient;

        public PostStream()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 释放资源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }

        private async void btnPostStream_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();

            try
            {
                // 需要 post 的 stream 数据
                Stream stream = GenerateSampleStream(128);
                StreamContent streamContent = new StreamContent(stream);

                HttpResponseMessage response = await _httpClient.PostAsync(
                   new Uri("http://localhost:39629/HttpDemo.aspx?action=postStream"),
                   streamContent);

                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;

                // HttpContent.ReadAsStringAsync() - 以 string 方式获取响应数据
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式获取响应数据
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式获取响应数据
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }

        // 生成一个指定大小的内存流
        private static MemoryStream GenerateSampleStream(int size)
        {
            byte[] subData = new byte[size];
            for (int i = 0; i < subData.Length; i++)
            {
                subData[i] = (byte)(97 + i % 26); // a-z
            }

            return new MemoryStream(subData);
        }

        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 请求
            _httpClient.CancelPendingRequests();
        }
    }
}


6、演示如何开发一个基于 OAuth 2.0 验证的客户端
Communication/OpenAuth/ClientDemo.xaml

<Page
    x:Class="XamlDemo.Communication.OpenAuth.ClientDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Communication.OpenAuth"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <Button Name="btnWeibo" Content="登录新浪微博,并返回登录用户好友最新发布的微博" Click="btnWeibo_Click" />

            <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

Communication/OpenAuth/ClientDemo.xaml.cs

/*
 * 演示如何开发一个基于 OAuth 2.0 验证的客户端
 * 
 * WebAuthenticationBroker - 用于 OAuth 2.0 验证的第一步,可以将第三方 UI 无缝整合进 app
 *     AuthenticateAsync(WebAuthenticationOptions options, Uri requestUri, Uri callbackUri) - 请求 authorization code,返回一个 WebAuthenticationResult 类型的数据
 *
 * WebAuthenticationResult - 请求 authorization code(OAuth 2.0 验证的第一步)的结果
 *     ResponseData - 响应的数据         
 *     ResponseStatus - 响应的状态
 *     
 * 
 * 关于 OAuth 2.0 协议参见:http://tools.ietf.org/html/draft-ietf-oauth-v2-20
 */

using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using Windows.Data.Json;
using Windows.Security.Authentication.Web;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace XamlDemo.Communication.OpenAuth
{
    public sealed partial class ClientDemo : Page
    {
        public ClientDemo()
        {
            this.InitializeComponent();
        }

        private async void btnWeibo_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var appKey = "39261162";
                var appSecret = "652ec0b02f814d514fc288f3eab2efda";
                var callbackUrl = "http://webabcd.cnblogs.com"; // 在新浪微博开放平台设置的回调页

                var requestAuthorizationCode_url = 
                    string.Format("https://api.weibo.com/oauth2/authorize?client_id={0}&response_type=code&redirect_uri={1}", 
                    appKey, 
                    callbackUrl);

                // 第一步:request authorization code
                WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
                    WebAuthenticationOptions.None,
                    new Uri(requestAuthorizationCode_url),
                    new Uri(callbackUrl));

                // 第一步的结果
                lblMsg.Text = WebAuthenticationResult.ResponseStatus.ToString() + Environment.NewLine;

                if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
                {
                    // 从第一步返回的数据中获取 authorization code
                    var authorizationCode = QueryString(WebAuthenticationResult.ResponseData, "code");
                    lblMsg.Text += "authorizationCode: " + authorizationCode + Environment.NewLine;

                    var requestAccessToken_url =
                        string.Format("https://api.weibo.com/oauth2/access_token?client_id={0}&client_secret={1}&grant_type=authorization_code&redirect_uri={2}&code={3}", 
                        appKey, 
                        appSecret,
                        callbackUrl,
                        authorizationCode);

                    // 第二步:request access token
                    HttpClient client = new HttpClient();
                    var response = await client.PostAsync(new Uri(requestAccessToken_url), null);

                    // 第二步的结果:获取其中的 access token
                    var jsonString = await response.Content.ReadAsStringAsync();
                    JsonObject jsonObject = JsonObject.Parse(jsonString);
                    var accessToken = jsonObject["access_token"].GetString();
                    lblMsg.Text += "accessToken: " + accessToken + Environment.NewLine;

                    var requestProtectedResource_url =
                        string.Format("https://api.weibo.com/2/statuses/friends_timeline.json?access_token={0}", 
                        accessToken);

                    // 第三步:request protected resource,获取需要的数据(本例为获取登录用户好友最新发布的微博)
                    var result = await client.GetStringAsync(new Uri(requestProtectedResource_url));
                    lblMsg.Text += "result: " + result;
                }
            }
            catch (Exception ex)
            {
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();

                // 由于本 app 没有提交新浪微博开放平台审核,所以需要在新浪微博开放平台中添加测试账号,否则会出现异常
            }
        }

        /// <summary>
        /// 模拟 QueryString 的实现
        /// </summary>
        /// <param name="queryString">query 字符串</param>
        /// <param name="key">key</param>
        private string QueryString(string queryString, string key)
        {
            return Regex.Match(queryString, string.Format(@"(?<=(\&|\?|^)({0})\=).*?(?=\&|$)", key), RegexOptions.IgnoreCase).Value;
        }  
    }
}

/*
 * OAuth 2.0 的 Protocol Flow
     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+
*/



OK
[源码下载]

目录
相关文章
|
Cloud Native 算法 区块链
站在巨人的肩膀上:gRPC通过HTTP/2构建云原生时代的通信标准
gRPC是云原生时代高效通信标准,基于HTTP/2实现,支持四种服务方法。通过.proto文件定义接口,生成多语言Stub,实现跨语言调用。其请求响应结构清晰,结合Headers、Data帧与Trailers,保障高性能与可扩展性,广泛应用于微服务架构中。
568 0
|
安全 算法 网络安全
SSL/TLS协议如何确保HTTP通信的安全
通过这些机制和过程,SSL/TLS对HTTP通信提供了强大的保护,确保数据不被未授权的第三方访问或篡改,这对维护数据隐私和网络安全至关重要。随着互联网技术的不断进步,SSL/TLS协议本身也在不断更新和升级,以对抗新出现的威胁和满足现代网络的要求。
515 10
|
C# Windows
【Azure App Service】在App Service for Windows上验证能占用的内存最大值
根据以上测验,当使用App Service内存没有达到预期的值,且应用异常日志出现OutOfMemory时,就需要检查Platform的设置是否位64bit。
436 11
HTTP 报文解构:深入剖析 HTTP 通信的核心要素
【10月更文挑战第21天】随着网络技术的不断发展和演进,HTTP 报文的形式和功能也可能会发生变化,但对其基本解构的理解始终是掌握 HTTP 通信的关键所在。无论是在传统的 Web 应用中,还是在新兴的网络技术领域,对 HTTP 报文的深入认识都将为我们带来更多的机遇和挑战。
|
Java 应用服务中间件 开发工具
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
344 2
|
Java 应用服务中间件 Windows
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
307 2
|
PHP Windows
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
439 1
|
网络安全 API 数据安全/隐私保护
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
344 0
|
Shell PHP Windows
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
377 0
|
存储 Linux Windows
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
270 0