• ASP.NET Web API基础(06)--- 使用C# 请求Web API及多版本控制


    6.1 C# 请求Web API的方式

    前端调用有Form表单提交,ajax提交,ajax一般是用Jquery的简化写法,在这里不再过多介绍; 后端调用大约有这些:WebCient、WebRequest、Httpclient、WebapiClient,重点探讨Get和Post请求,Put和Delete请求用较少。

    下面先介绍Get和Post的基本写法,最后再封装一下,便于调用。

    先编写几个服务器端的接口方法,便于调用。

            [HttpGet]

            public string CheckLogin(string userName, string pwd)

            {

                if (userName == "admin" && pwd == "123456")

                {

                    return "ok";

                }

                else

                {

                    return "error";

                }

            }

            [HttpPost]

            public string Register([FromBody]LoginModel model)

            {

                if (model.userName == "admin" && model.pwd == "123456")

                {

                    return "ok";

                }

                else

                {

                    return "error";

                }

            }

            [HttpPost]

            public string Register2([FromBody]dynamic model)

            {

                if (model.userName == "admin" && model.pwd == "123456")

                {

                    return "ok";

                }

                else

                {

                    return "error";

                }

            }

    为了方便下面的测试,给上述三个地址进行命名描述和序列化方法的初始化

     

    6.1.1 WebClient

    1. Get 请求

    WebClient wc = new WebClient();

    string url = url1;

    wc.Encoding = Encoding.UTF8;

    string result = wc.DownloadString(url);

    Console.WriteLine(result);

    Console.ReadKey();

    2. Post的表单提交方式

    WebClient wc = new WebClient();

      string url = url3;

      wc.Encoding = Encoding.UTF8;

      //也可以向表头中添加一些其他东西

      wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

      string result = wc.UploadString(url, "userName=admin&pwd=123456");

      Console.WriteLine(result);

      Console.ReadKey();

    3. Post的JSON提交格式

    var user = new

                {

                   userName = "admin",

                   pwd = "123456"

                };

     WebClient wc = new WebClient();

     string url = url3;

     wc.Encoding = Encoding.UTF8;

     wc.Headers.Add("Content-Type", "application/json");

     string result = wc.UploadString(url, jss.Serialize(user));

     Console.WriteLine(result);

     Console.ReadKey();

    6.1.2 WebRequest

    1. Get请求

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url1);

     request.Timeout = 30 * 1000;

     request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36";

     request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";

     string result = "";

     using (var res = request.GetResponse() as HttpWebResponse)

     {

        if (res.StatusCode == HttpStatusCode.OK)

        {

           StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8);

           result = reader.ReadToEnd();

        }

     }

     Console.WriteLine(result);

     Console.ReadKey();

    2. Post的表单提交方式

    var postData = "userName=admin&pwd=123456";

    var request = HttpWebRequest.Create(url2) as HttpWebRequest;

    request.Timeout = 30 * 1000;//设置30s的超时

    request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36";

    request.ContentType = "application/x-www-form-urlencoded";

    request.Method = "POST";

    byte[] data = Encoding.UTF8.GetBytes(postData);

    request.ContentLength = data.Length;

    Stream postStream = request.GetRequestStream();

    postStream.Write(data, 0, data.Length);

    postStream.Close();

    string result = "";

    using (var res = request.GetResponse() as HttpWebResponse)

    {

         if (res.StatusCode == HttpStatusCode.OK)

         {

             StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8);

             result = reader.ReadToEnd();

         }

    }

    Console.WriteLine(result);

    Console.ReadKey();

    3. Post的JSON提交格式

    var user = new

    {

         userName = "admin",

         pwd = "123456"

    };

    var postData = jss.Serialize(user);

    var request = HttpWebRequest.Create(url2) as HttpWebRequest;

    request.Timeout = 30 * 1000; //设置30s的超时

    request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36";

    request.ContentType = "application/json";

    request.Method = "POST";

    byte[] data = Encoding.UTF8.GetBytes(postData);

    request.ContentLength = data.Length;

    Stream postStream = request.GetRequestStream();

    postStream.Write(data, 0, data.Length);

    postStream.Close();

    string result = "";

    using (var res = request.GetResponse() as HttpWebResponse)

    {

         if (res.StatusCode == HttpStatusCode.OK)

         {

            StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8);

            result = reader.ReadToEnd();

         }

    }

    Console.WriteLine(result);

    Console.ReadKey();

    6.1.3 HttpClient

    1. Get请求

    var handler = new HttpClientHandler();

    using (var http = new HttpClient(handler))

    {

         var response = http.GetAsync(url1).Result;

         //获取Http的状态值

         //Console.WriteLine(response.StatusCode);

         string result = response.Content.ReadAsStringAsync().Result;

         Console.WriteLine(result);

         Console.ReadKey();

    }

    2. Post的表单提交方式

    var handler = new HttpClientHandler();

    using (var http = new HttpClient(handler))

    {

         var content = new StringContent("userName=admin&pwd=123456", Encoding.UTF8, "application/x-www-form-urlencoded");

         var response = http.PostAsync(url2, content).Result;

         //获取Http的状态值

         //Console.WriteLine(response.StatusCode);

         string result = response.Content.ReadAsStringAsync().Result;

         Console.WriteLine(result);

         Console.ReadKey();

    }

    3. Post的JSON提交格式

    var user = new

    {

        userName = "admin",

        pwd = "123456"

    };

    var handler = new HttpClientHandler();

    using (var http = new HttpClient(handler))

    {

       var content = new StringContent(jss.Serialize(user), Encoding.UTF8, "application/json");

       var response = http.PostAsync(url3, content).Result;

       //获取Http的状态值

       //Console.WriteLine(response.StatusCode);

       string result = response.Content.ReadAsStringAsync().Result;

       Console.WriteLine(result);

       Console.ReadKey();

    }

    以上代码均是官方的给出的标准写法,但存在很严重的问题,当请求量大的时候,会存在不能释放的问题 。

    目前使用的比较多的是HttpClient,它适合用于多次请求操作。将HttpClient做成单例的,不用Using,全局只有一个,来解决tcp连接不能释放的问题。此外,HttpClient提供了异步支持,可以轻松配合async await 实现异步请求。

    工厂类,单例。

    /// <summary>

        /// 将HttpClient做成单例的,不用Using,全局只有一个

        /// 来解决tcp连接不能释放的问题

        /// </summary>

        public class HttpClientFactory

        {

            private static HttpClient _httpClient = null;

            /// <summary>

            /// 静态的构造函数:只能有一个,且是无参数的

            /// 由CLR保证,只有在程序第一次使用该类之前被调用,而且只能调用一次

            /// 说明: keep-alive关键字可以理解为一个长链接,超时时间也可以在上面进行设置,例如10秒的超时时间,当然并发量太大,这个10秒应该会抛弃很多请求

            /// 发送请求的代码没有了using,即这个httpclient不会被手动dispose,而是由系统控制它,当然你的程序重启时,这也就被回收了。

            /// </summary>

            static HttpClientFactory()

            {

                _httpClient = new HttpClient(new HttpClientHandler());

                _httpClient.Timeout = new TimeSpan(0, 0, 10);

                _httpClient.DefaultRequestHeaders.Connection.Add("keep-alive");

            }

            /// <summary>

            /// 对外开放接口

            /// </summary>

            /// <returns></returns>

            public static HttpClient GetHttpClient()

            {

                return _httpClient;

            }

        }

    对HttpClient的封装

    public class HttpClientHelper

        {

            /// <summary>

            /// HttpClient的Get请求

            /// </summary>

            ///<param name="url">请求地址,含拼接数据 </param>

            /// <returns></returns>

            public static string Get(string url)

            {

                var http = HttpClientFactory.GetHttpClient();

                var response1 = http.GetAsync(url).Result;

                return response1.Content.ReadAsStringAsync().Result;

            }

             /// <summary>

            /// HttpClient的Post请求

            /// 表单提交模式[application/x-www-form-urlencoded]

            /// </summary>

            /// <param name="url">请求地址,单纯的地址,没有数据拼接</param>

            /// <param name="data">请求数据,格式为:"userName=admin&pwd=123456"</param>

            /// <returns></returns>

            public static string PostForm(string url, string data)

            {

                var http = HttpClientFactory.GetHttpClient();

                var content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");

                var response = http.PostAsync(url, content).Result;

                return response.Content.ReadAsStringAsync().Result;

            }

            #endregion

            /// <summary>

            /// HttpClient的Post请求

            /// Json提交模式[application/json]

            /// </summary>

            /// <param name="url">请求地址,单纯的地址,没有数据拼接</param>

            /// <param name="data">请求数据,格式为(Json)对象、或者类对象 </param>

            /// <returns></returns>

            public static string PostJSON(string url, object data)

            {

               

                var http = HttpClientFactory.GetHttpClient();

                var content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");

                var response = http.PostAsync(url, content).Result;

                return response.Content.ReadAsStringAsync().Result;

            }

            #endregion

        }

    6.2 多版本控制

    6.2.1 多版本管理的概念

    Android 、IOS等 App 存在着多版本客户端共存的问题:App 最新版已经升级到了5.0 了,但是有的用户手机上还运行着 4.8、3.9 甚至2.2 版本的 App,由于早期没有内置升级机制、用户不会升级、用户拒绝升级等原因,造成这些旧版本 App 也在运行。开发新版本 App 的时候,要给接口增加新的功能或者修改以前接口的规范,会造成旧版本App 无法使用,因此在一定情况下会“保留旧接口的运行、新功能用新接口”,这样就会存在多版本接口共存的问题。

    通常的做法是:旧版接口做一个代码分支,除了进行 bug 修改外,旧版本接口不再做改动,新接口代码继续演化升级。在客户端请求的时候带着要请求的接口版本号,在服务器端选择合适的版本代码进行处理。

    6.2.2 多版本解决方案

    1. 不同的版本使用不同的域名:v1.api.ypf.com、v2.api.ypf.com、v3……  (最佳方案)
    2. 在Url,报文头等中带不同的版本信息,用Nginx等做反向代理服务,然后将 http://api.ypf.com/api/v1/User/1和http://api.ypf.com/api/v2/User/1 转到不同的服务器处理。
    3. 多个版本的 Controller共处在一个项目中,然 后使 用 [RoutePrefix] 特性来进行区分,这种方案Controller的名字不能一样,如下:

     

          4. 如果我想在Controller文件夹中新建多个版本文件夹,如:v1、v2、v3,每个文件夹中存放的控制器名称相同,比如都叫PersonController,不同文件夹下代表不同版本,这个时候会有一个很尴尬的问题,没法请求,识别不了,这个时候就需要重写系统默认的机制,IHttpControllerSelector 根据 “报文头”或者“请求路径”等选择不同的 Controller 执行。

     

  • 相关阅读:
    cdn与http缓存
    EntityFramework、Dapper vs 草根框架性能
    docker10件事
    TCP的阻塞和重传
    ngCookies模块
    Net Core- 配置组件
    获取synchronized锁中的阻塞队列中的线程是非公平的
    Java线程并发中常见的锁--自旋锁 偏向锁
    byte为什么要与上0xff(转)
    Tair是一个高性能,分布式,可扩展,高可靠的key/value结构存储系统(转)
  • 原文地址:https://www.cnblogs.com/mrfang/p/13911818.html
Copyright © 2020-2023  润新知