微信小程序給我們提供了一個很好的開發平臺,可以用于展現各種數據和實現豐富的功能,通過小程序的請求Web API 平臺獲取JSON數據后,可以在小程序界面上進行數據的動態展示。在數據的關鍵 一環中,我們設計和編寫Web API平臺是非常重要的,通過這個我們可以實現數據的集中控制和管理,本篇隨筆介紹基于Asp.NET MVC的Web API接口層的設計和常見接口代碼的展示,以便展示我們常規Web API接口層的接口代碼設計、參數的處理等內容。
1、Web API整體性的架構設計
我們整體性的架構設計,包含一個Web管理后臺、一個Web API統一接口層、當然還有數據庫什么,另外還有一個小程序客戶端。整個架構體系還是以我之前隨筆介紹的《整合微信小程序的Web API接口層的架構設計》內容為藍本
整個體系以Web API為主提供服務,同時后臺管理系統通過各種界面維護著數據的增刪改等基礎管理工作。
Web API的分層,我們可以通過下圖來了解具體的分層結構。
隨著基于JSON格式的Web API的廣泛應用,越來越多的企業采用Web API接口服務層,作為統一接口的核心所在,也成為Web API核心層。基于JSON格式的接口,可以廣泛地、跨平臺的應用于IOS、安卓等移動端,也可以應用在常規的Web業務系統,Winform業務系統、微信應用、微信小程序等方方面面,因此企業內部形成自己是的一套Web API標準和詳細的文檔非常重要。
我們可以細化為下面的架構設計圖,所有模塊均圍繞著Web API 接口層進行擴展,底層的數據存儲對上層的應用是完全透明,我們可以根據需要拆分各種業務數據庫,以及使用我們認為合適的數據庫。
其中我們在Web API接口層上還看到一個微信消息交互的模塊,這個模塊我們為了方便域名端口的處理,和Web API 是統一放在一起的,它負責和騰訊微信服務器進行消息的交互處理,從而實現各種消息推送處理。
2、基于Asp.NET MVC的Web API接口的實現
1)GET方式
GET方式,接口參數包括有零或一個參數,以及多個參數的方式,返回的值可以是簡單的字符串等基礎類型,也可以是復雜的自定義對象類型等,如下面幾種接口代碼所示。
/// <summary>
/// 簡單的GET方式獲取數據
/// </summary>
/// <param name="id">字符串ID</param>
/// <param name="token">接口訪問令牌</param>
/// <returns>返回字符串值</returns>
[HttpGet]
public string Test(string id, string token)
{
return string.Format("返回結果, id:{0}", id);
}
/// <summary>
/// 多個參數的GET方式獲取數據
/// </summary>
/// <param name="id">字符串ID</param>
/// <param name="name">名稱</param>
/// <param name="token">接口訪問令牌</param>
/// <returns>返回字符串值</returns>
[HttpGet]
public string TestMulti(string id, string name, string token)
{
return string.Format("返回結果, id:{0} name:{1}", id, name);
}
/// <summary>
/// 參數測試GET返回自定義實體類對象
/// </summary>
/// <param name="id">字符串ID</param>
/// <param name="token">接口訪問令牌</param>
/// <returns>返回自定義實體類對象</returns>
[HttpGet]
public virtual CommonResult TestObject(string id, string token)
{
return new CommonResult() { Data1 = id, Success = true };
}
/// <summary>
/// 測試GET返回列表對象
/// </summary>
/// <param name="token">接口訪問令牌</param>
/// <returns>返回列表對象</returns>
[HttpGet]
public List<string> TestAction(string token)
{
List<string> list = new List<string>() { "123", "234", "345" };
return list;
}
2)POST方式
POST方式,同樣也和GET方式的一樣,接口參數包括有零或一個參數,以及多個參數的方式,返回的值可以是簡單的字符串等基礎類型,也可以是復雜的自定義對象類型等,這就是幾種常規的接口處理。但是,對于多個參數的接口定義,我們需要對它們進行轉換處理,需要使用JObject param的方式進行定義,這樣可以很好對多個參數或者自定義的實體類參數進行解析。
下面是幾種常規的POST接口定義方式。
/// <summary>
/// 測試使用POST方式提交數據,參數輸入為多個,使用JObject處理
/// </summary>
/// <returns>返回字符串</returns>
[HttpPost]
public string TestPost(JObject param, string token)
{
dynamic obj = param;
string id = obj.id;
if (obj != null)
{
return string.Format("返回結果, id:{0}", id);
}
else
{
throw new MyApiException("傳遞參數出現錯誤");
}
}
/// <summary>
/// 測試使用POST方式提交數據,參數輸入為多個,使用JObject處理
/// </summary>
/// <returns>返回參數計算數值</returns>
[HttpPost]
public int TestPostSimple(JObject param)
{
dynamic obj = param;
if (obj != null)
{
return obj.x * obj.y * 10;
}
else
{
throw new MyApiException("傳遞參數出現錯誤");
}
}
/// <summary>
/// 測試POST的方法,方法統一采用JObject param 方式定義,包含一個msg字符串對象,以及一個CListItem對象
/// </summary>
/// <returns>返回一個通用的CommonResult對象,包括Data1,Data2,Data3的信息</returns>
[HttpPost]
public CommonResult TestPostObject(JObject param)
{
dynamic obj = param;
if (obj != null)
{
string msg = obj.msg; //消息對象
//如果obj.item為類對象,那么需要轉換為JObject然后使用ToObject轉換為對應類型
CListItem item = ((JObject)obj.item).ToObject<CListItem>();
var result = new CommonResult(true, msg);
result.Data1 = msg;
result.Data2 = item.Text;
result.Data3 = item.Value;
return result;
}
else
{
throw new MyApiException("傳遞參數出現錯誤");
}
}
/// <summary>
/// 修改分組,方法統一采用JObject param 方式定義,包括一個字符串對象contactId,一個字符串列表對象groupIdList
/// </summary>
/// <returns>返回一個通用的對象</returns>
[HttpPost]
public CommonResult TestPostList(JObject param)
{
dynamic obj = param;
if (obj != null)
{
string contactId = obj.contactId; //聯系人ID
//如果是List<string>的類似列表,不能直接轉換,先轉換為JArray后使用ToObject轉換為對應列表
List<string> groupIdList = ((JArray)obj.groupIdList).ToObject<List<string>>();
var result = true; //BLLFactory<Address>.Instance.ModifyAddressGroup(contactId, groupIdList);
return new CommonResult(result);
}
else
{
throw new MyApiException("傳遞參數出現錯誤,請檢查是否包含了contactId和groupIdList");
}
}
接口類,我們一般把類繼承自自己的API接口基類,并對它的異常處理進行處理,以便對錯誤統一格式回應,如下接口類的代碼定義所示。
/// <summary>
/// 此控制器用來詳細介紹各種GET/POST的接口設計
/// 對于GET方式,方法可以接受多個參數
/// 對于POST方式,方法如果有參數使用POST方式,統一采用JObject param對象參數。
/// 如果POST方式有多個參數,如Web API接口加token,則需要客戶端把該參數追加在URL上,如url?token=123,然后在使用POST操作
/// </summary>
[ExceptionHandling]
public class TestController : BaseApiController
其中ExceptionHandling是我們的統一異常過濾處理定義,代碼如下所示。
/// <summary>
/// API自定義錯誤過濾器屬性
/// </summary>
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
/// <summary>
/// 統一對調用異常信息進行處理,返回自定義的異常信息
/// </summary>
/// <param name="context">HTTP上下文對象</param>
public override void OnException(HttpActionExecutedContext context)
{
//自定義異常的處理
MyApiException ex = context.Exception as MyApiException;
if (ex != null)
{
//記錄關鍵的異常信息
LogHelper.Error(context.Exception);
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
//封裝處理異常信息,返回指定JSON對象
Content = new StringContent(new BaseResultJson(ex.Message, false, ex.errcode).ToJson()),
ReasonPhrase = "Exception"
});
}
//常規異常的處理
string msg = string.IsNullOrEmpty(context.Exception.Message) ? "接口出現了錯誤,請重試或者聯系管理員" : context.Exception.Message;
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(msg),
ReasonPhrase = "Critical Exception"
});
}
}
3)小程序端代碼處理
小程序端主要是通過JS代碼進行處理,實現數據的獲取及提交處理等。
如我們列舉一個代表性的POST處理代碼,如下所示。
//測試POst方法
wx.request({
url: 'http://localhost:27206/api/SmallApp/Test/TestPostObject',
data: {
msg : '測試內容',
item: {Text :'Text', Value:'testValue'}
},
header: {'Content-Type': 'application/json' },
method: 'POST',
success: function (res) {
console.log(res.data);
}
});
而對于GET方式,我們的小程序調用方式如下所示。
getFilms: function(start) {
console.log('start:' + start);
var that = this
wx.request({
url: 'http://www.iqidi.com/api/h5/test/movies',
data: {
offset: start,
type: 'hot',
limit: that.data.limit
},
header: {
'Content-Type': 'application/json'
},
success: function (res) {
console.log(res.data)
var data = res.data.data;
console.log(data);
if (data.movies.length === 0) {
that.setData({
hasMore: false,
hideLoading :true,
})
}
else {
that.setData({
films: that.data.films.concat(data.movies),
start: that.data.start + data.movies.length,
hasMore: true,
hideLoading :true,
});
}
}
})
以上就是我們常規接口(單個參數或者多個參數,簡單對象和復雜對象的處理)的定義代碼,希望讀者在開發Web API接口的時候,可以有所幫助。