1. 文章目的

随着WebApiClient的不断完善,越来越多开发者选择WebApiClient替换原生的HttpClient,然而在应用到实际项目中多多少少会遇到一些项目结合上的疑问和困难,本文将以WebApiClient使用者的身份,在Asp.net core mvc项目中使用WebApiClient来请求百度地图服务接口,以展示WebApiClient的使用技巧。

2. 百度地图服务接口

  1. 静态图接口

    http://api.map.baidu.com/staticimage/v2?ak=你的密钥&mcode=666666&center=116.403874,39.914888&width=300&height=200&zoom=11

  2. 坐标转换接口

    http://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak=你的密钥

3. 接口分析

通过分析百度地图的接口,我们发现:

  • 所有接口都在api.map.baidu.com这个域名上;
  • ak参数是一个客户端身份标识的参数,所有请求接口都需要附加这个ak值;
  • 接口中需要的116.403874,39.914888这种参数值,实际是(经度,纬度),为两个值组成;
  • from和to是枚举数值类型;

在我们进行Coding的时候,应该重点考虑这些共性,以减少重复的工作内容。

4. 接口声明

4.1 公共域名

[HttpHost("http://api.map.baidu.com/")]
public interface IBdMapApi : IHttpApi
{
}

4.2 公共的AK参数

我们要实现一个接口级或方法级的ApiAction特性,用于给请求路径增加公共的ak参数:

/// <summary>
/// 表示百度AK信息
/// </summary>
public class AkAttribute : ApiActionAttribute
{
private readonly string ak; /// <summary>
/// 百度AK信息
/// 执行时追加到请求query
/// </summary>
/// <param name="ak"></param>
public AkAttribute(string ak)
{
this.ak = ak;
} /// <summary>
/// 请求前
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task BeforeRequestAsync(ApiActionContext context)
{
context.RequestMessage.AddUrlQuery("ak", this.ak);
await Task.CompletedTask;
}

然后把Ak特性追加到接口上:

[HttpHost("http://api.map.baidu.com/")]
[Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")]
public interface IBdMapApi : IHttpApi
{
}

4.3 静态图staticimage接口

参照接口文档,声明最初的StaticImage接口:

[HttpGet("staticimage/v2")]
ITask<Stream> StaticImageAsync(
string center,
int width = 300,
int height = 200,
int zoom = 11,
int mcode = 666666);

目前center参数是string类型,约束性非常弱,与接口要求的(经度,纬度)这种格式数据差异比较大。所以我们应该定一个继承自IApiParameterable的BdLocation类型,将传入的经度和纬度转换为这种文本格式:

/// <summary>
/// 表示位置信息
/// </summary>
public class BdLocation : IApiParameterable
{
/// <summary>
/// 获取位置值
/// </summary>
public string Value { get; private set; } /// <summary>
/// 位置信息
/// 执行时追加到请求query
/// </summary>
/// <param name="lng">经</param>
/// <param name="lat">纬</param>
public BdLocation(decimal lng, decimal lat)
{
this.Value = $"{lng},{lat}";
} public override string ToString()
{
return this.Value;
} /// <summary>
/// 自解释模式
/// </summary>
/// <param name="context"></param>
/// <param name="parameter"></param>
/// <returns></returns>
Task IApiParameterable.BeforeRequestAsync(ApiActionContext context, ApiParameterDescriptor parameter)
{
context.RequestMessage.AddUrlQuery(parameter.Name, this.Value);
return Task.CompletedTask;
}
}

修改后StaticImage接口修改为:

[HttpGet("staticimage/v2")]
ITask<Stream> StaticImageAsync(
BdLocation center,
int width = 300,
int height = 200,
int zoom = 11,
int mcode = 666666);

4.4 坐标转换Geoconv接口

依照文档,编写出最初的接口

[HttpGet("geoconv/v1/")]
ITask<string> GeoconvAsync(
string coords,
int from = 1,
int to = 5);

和StaticImage接口一样,我们还需要合理修改这个接口的参数约束,coords实际为BdLocation类型, from和to可以修改为枚举类型,返回值string修改为强类型的模型,修改后的接口为:

[HttpGet("geoconv/v1/")]
ITask<BdResult<BdPoint[]>> GeoconvAsync(
BdLocation coords,
BdFrom from = BdFrom.wgs84,
BdTo to = BdTo.bd09ll);

4.5 完整的接口声明

/// <summary>
/// 定义百度地图接口
/// </summary>
[Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")]
[HttpHost("http://api.map.baidu.com/")]
public interface IBdMapApi : IHttpApi
{
/// <summary>
/// 静态图
/// </summary>
/// <param name="center"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="zoom"></param>
/// <param name="mcode"></param>
/// <returns></returns>
// http://api.map.baidu.com/staticimage/v2?ak=你的密钥&mcode=666666&center=116.403874,39.914888&width=300&height=200&zoom=11
[HttpGet("staticimage/v2")]
ITask<Stream> StaticImageAsync(
BdLocation center,
int width = 300,
int height = 200,
int zoom = 11,
int mcode = 666666); /// <summary>
/// 坐标转换
/// </summary>
/// <param name="coords"></param>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns></returns>
// http://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak=你的密钥 //GET请求
[HttpGet("geoconv/v1/")]
ITask<BdResult<BdPoint[]>> GeoconvAsync(
BdLocation coords,
BdFrom from = BdFrom.wgs84,
BdTo to = BdTo.bd09ll);
}

5. 接口的依赖注入

WebApiClient的HttpApiClient创建的代理实例,适合使用单例模式,在支持依赖注入的项目开发中,应尽量使用依赖注入来完成HttpApiClient的创建和生命周期管理。

5.1 Asp.net core的依赖注入

在ConfigureServices方法里添加IBdMapApi的注入配置

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(HttpApiClient.Create<IBdMapApi>());
......
}

如果项目里声明了很多接口,比如IBaiduApi、ITengxunApi等等,可以循环批量注入:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var apis = this.GetType().Assembly.GetTypes().Where(item => typeof(IHttpApi).IsAssignableFrom(item));
foreach (var api in apis)
{
services.AddSingleton(api, HttpApiClient.Create(api, new HttpApiConfig()));
}
}

5.2 接收和使用IBdMapApi代理实例

public class HomeController : Controller
{
private readonly IBdMapApi bdMapApi; public HomeController(IBdMapApi bdMapApi)
{
this.bdMapApi = bdMapApi;
} public async Task<IActionResult> Index()
{
var image = await this.bdMapApi.StaticImageAsync(new BdLocation(116.403874m, 39.914888m));
var geoResult = await this.bdMapApi.GeoconvAsync(new BdLocation(116.403874m, 39.914888m)); return View();
}
}

6. 监视请求提交的内容

WebApiClient对Http请求进行的高度抽象,只有声明,没有实现,在没有熟悉WebApiClient的情况下,我们开发中可能需要在请求发送的内容进行监视,从而知道是否符合服务器的接口数据要求。在不使用第三方工具比如Fiddler等的情况下,我们可以为接口修饰一个自定义过滤器,在过滤器里实现访打印求消息内容的能力。

6.1 定义TraceFilter过滤器

/// <summary>
/// 请求内容追踪过滤器
/// </summary>
public class TraceFilter : ApiActionFilterAttribute
{
/// <summary>
/// 打印请求内容
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task OnBeginRequestAsync(ApiActionContext context)
{
var request = await context.RequestMessage.ToStringAsync();
System.Diagnostics.Debug.Print(request);
}
}

6.2 接口关联TraceFilter

/// <summary>
/// 定义百度地图接口
/// </summary>
[TraceFilter]
[Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")]
[HttpHost("http://api.map.baidu.com/")]
public interface IBdMapApi : IHttpApi
{
}

6.3 查看请求内容

开启程序调试,输出窗口里打印

GET /staticimage/v2?ak=qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc&center=116.403874%2c39.914888&width=300&height=200&zoom=11&mcode=666666 HTTP/2.0
Host: api.map.baidu.com GET /geoconv/v1/?ak=qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc&coords=116.403874%2c39.914888&from=1&to=5 HTTP/2.0
Host: api.map.baidu.com

7. 结束语

博主为WebApiClient库的作者,致力于站在使用者的角度去设计WebApiClient,欢迎大家给WebApiClient提建议。

WebApiClient百度地图服务接口实践的更多相关文章

  1. httpclient案例二(调用百度地图的接口)

    一,class T package com.http.test; import org.junit.Test; import com.http.BaiduMapProxyService; import ...

  2. 简单几行代码使用百度地图API接口分页获取信息

    首发于: 万能助手扩展开发:使用百度地图API接口分页获取信息_电脑计算机编程入门教程自学 http://jianma123.com/viewthread.aardio?threadid=426 使用 ...

  3. Angular 调用百度地图API接口

    Angular 调用百度地图API接口 参考原文:https://blog.csdn.net/yuyinghua0302/article/details/80624274 下面简单介绍一下如何在Ang ...

  4. tp5 封装百度地图api接口

    //服务器端api extend\Map <?php /** * 百度地图业务封装 */ class Map{ /** * 根据地址来获取经纬度 * @param $address */ pub ...

  5. 百度云服务接口错误:Parameter invalid, the key input with filter parameter is not searchfilter column key

    百度LBS云服务接口: 地址:http://lbsyun.baidu.com/index.php?title=lbscloud/api/geosearch 访问接口:http://api.map.ba ...

  6. 百度地图API应用实践(一) —— 栅格图(草稿)

    概述 运用百度地图JS API,实现了在百度地图上绘制栅格并按统计值渲染栅格颜色.实现的过程是不断补习的过程,其中用到一些技术,是个人首次尝试.包括:(1)简单的jQuery语法,并实现Ajax:(2 ...

  7. 百度地图HTML接口

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. 百度地图LV1.5实践项目开发工具类bmap.util.jsV1.3

    /** * 百度地图使用工具类-v1.5 * * @author boonya * @date 2013-7-7 * @address Chengdu,Sichuan,China * @email b ...

  9. 百度地图LV1.5实践项目开发工具类bmap.util.jsV1.2

    /** * 百度地图使用工具类-v1.5 * * @author boonya * @date 2013-7-7 * @address Chengdu,Sichuan,China * @email b ...

随机推荐

  1. 【二分贪心】Bzoj3969 [WF2013] Low Power

    Description 有n个机器,每个机器有2个芯片,每个芯片可以放k个电池. 每个芯片能量是k个电池的能量的最小值. 两个芯片的能量之差越小,这个机器就工作的越好. 现在有2nk个电池,已知它们的 ...

  2. Python数据结构应用6——树

    数据结构中的树的结点和机器学习中决策树的结点有一个很大的不同就是,数据结构中的树的每个叶结点都是独立的. 树的高度(Height)指叶结点的最大层树(不包含根结点) 一.树的建立 树可以这样定义:一棵 ...

  3. Javascript保证精度的小数乘法

    众所周知,js的小数乘法很容易丢失精度,这是一件很恶心的事情.所以我写了这个方法,保证计算精度./** * js小数乘法 *@parameter arg1:被乘数(接受小数和整数) *@paramet ...

  4. Postman----request的body中实现数据驱动

    使用场景: 一个接口多次执行,要求body中的某个参数在每次运行时都要填写不同的值,根据不同值的传入,返回不同的结果 参考示例:通过接口测试创建5条待办名称不一样的待办事项.名称格式不作要求 解决方法 ...

  5. CountDownLatch和CyclicBarrier 区别

    CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行. CyclicBarrier        : N个线程相互等待,任何一个线程完成之前,所有的线程都 ...

  6. CMake入门实战

    本文用来记录基本的Cmake用法,以一个实例,讲解如何通过cmake构建一个一个基本的工程,文件的目录如下: 说明: bin文件夹下的debug和release分别存放编译输出的文件和相关依赖的动态库 ...

  7. ssh框架整合笔记

    1.建立普通的Javaweb项目,导入项目所必须的jar包. 2.配置web.xml文件. web.xml  3.在src下建立struts.xml. struts.xm 4.在实体包下配置  实体名 ...

  8. java常用的框架介绍

    一.SpringMVC http://blog.csdn.net/evankaka/article/details/45501811 Spring Web MVC是一种基于Java的实现了Web MV ...

  9. 神奇的Scala Macro之旅(一)- 什么时候用宏

    在Lisp语言中,macro是一个神器,可以“动态的生成代码”,然后被执行,这种方式给到Lisp无限的表达能力.除Lisp之外,很少有语言支持Macro这个特性,我记得 GWT之中曾经有一个类似的Ge ...

  10. Windows下Goland的Terminal设置为Git Bash

    Windows下Terminal默认的使用的是系统自带的cmd,功能实在太少,用起来远不如Git Bash来得方利和高效.其实要在Goland的Terminal中使用Bash设置起来也很简单,设置位置 ...