【整理】使用web api開發微信公衆號,調用圖靈機器人接口(二)

此文將分兩篇講解,主要分爲以下幾步

  1. 簽名校驗;
  2. 首次提交驗證申請;
  3. 接收消息;
  4. 被動響應消息(返回XML);
  5. 映射圖靈消息及微信消息;

此篇爲第二篇。

被動響應消息(返回XML)

上一篇中,我們已經可以拿到了微信傳入的參數,接下來,我們需要響應消息給用戶。

微信要求我們返回XML數據,且格式是規定好的,具體請看 微信公衆平臺開發者文檔

響應的實體類,我們之前已經寫好了,因爲要求是XML格式。 我們在此使用微軟提供的System.Xml.Serialization.XmlSerializer來將我們的數據序列化爲XML。 所以我們在類上邊標記了XmlRoot特性,在枚舉的字段上邊標記了XmlEnum特性,NewsMsg中在文章列表上標記了XmlArrayXmlArrayItem特性。而後反序列化出來的便是微信要求的格式了。

序列化方法如下:

public string ResponseXML(object value, Type type)
{
    StringWriter sw = new StringWriter();
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

    ns.Add("", "");  //去除命名空間
    XmlSerializer serializer = new XmlSerializer(type);

    serializer.Serialize(sw, value, ns);

    return sw.ToString();
}

 注意:此處必須去除XML的命名空間,不然微信不識別

完整方法奉上:

public HttpResponseMessage Post()
{
    var requestContent = Request.Content.ReadAsStreamAsync().Result;
    //從正文參數中加載微信的請求參數
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(requestContent);

    logger.DebugFormat("WX請求XML內容:{0}", xmlDoc.InnerText);

    string msgTypeStr = xmlDoc.SelectSingleNode("xml/MsgType").InnerText;
    string userName = xmlDoc.SelectSingleNode("xml/FromUserName").InnerText;
    string efhName = xmlDoc.SelectSingleNode("xml/ToUserName").InnerText;

    string responseContent;
    MsgType msgType;

    //獲取消息類型,若未定義,則返回。
    if (!Enum.TryParse(msgTypeStr, true, out msgType))
    {           
        responseContent = MsgService.Instance.ResponseXML(new TextMsg
            {
                FromUserName = efhName,
                MsgType = MsgType.Text,
                Content = "俺還小,不知道你在說啥子(⊙_⊙)?",
                CreateTime = UnixTimestamp.Now.ToNumeric(),
                ToUserName = userName
            }, typeof(TextMsg));

        return new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(responseContent, Encoding.UTF8, "application/xml"),
        };
    }

    if (msgType == MsgType.Event)
    {
        return ProcessEvent(xmlDoc, userName, efhName);
    }

    //圖靈消息轉換爲微信響應消息,下一節奉上
    string content = xmlDoc.SelectSingleNode("xml/Content").InnerText;
    var requestResult = TuLingService.Instance.GetMsgFromResponse(content, userName, efhName);

    responseContent = MsgService.Instance.ResponseXML(requestResult.Data, requestResult.DataType);
    return new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent(responseContent, Encoding.UTF8, "application/xml"),
    };
}

private HttpResponseMessage ProcessEvent(XmlDocument xmlDoc, string userName, string efhName)
{
    string eventValue = xmlDoc.SelectSingleNode("xml/Event").InnerText;

    var responseContent = MsgService.Instance.ResponseXML(new TextMsg
    {
        FromUserName = efhName,
        MsgType = MsgType.Text,
        Content = eventValue.ToLower().Equals("subscribe") ? "lei好哇~" : "大爺,奴家會想你的",//其實取消訂閱是不會發送消息的
        CreateTime = UnixTimestamp.Now.ToNumeric(),
        ToUserName = userName
    }, typeof(TextMsg));

    return new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent(responseContent, Encoding.UTF8, "application/xml"),
    };
}

 至此,我們已經完成了微信被動回覆消息的響應。

映射圖靈消息及微信消息

上邊我們已經實現了被動回覆消息的功能,接下來我們需要將圖靈機器人接口與我們的公衆平臺關聯起來。

分析圖靈機器人返回的參數,我們發現所有類型的內容都有codetext參數。又因爲我們需要將圖靈的消息與微信的響應消息直接對應起來,因此我們定義接口,提供轉換方法

public class TuLingResult
{
    //消息類型(我們在序列化爲XML的時候需要提供類型)
    public Type DataType { get; set; }

    public object Data { get; set; }
}
public interface IResponse
{
    TuLingResult ToTuLingResult(string fromUserName, string toUserName);
}

 創建文本類數據的實體作爲圖靈消息的基類(對應微信的文本消息)

public class TextResult : IResponse
{
    public int Code { get; set; }

    public string Text { get; set; }

    public virtual TuLingResult ToTuLingResult(string fromUserName, string toUserName)
    {
        return new TuLingResult
        {
            DataType = typeof(TextMsg),
            Data = new TextMsg
             {
                 FromUserName = fromUserName,
                 ToUserName = toUserName,
                 Content = Text,
                 CreateTime = UnixTimestamp.Now.ToNumeric(),
                 MsgType = MsgType.Text
             }
        };
    }
}

 而後依次創建各種數據的實體類。

如:新聞(對應微信的圖文消息)

public class NewsResult : TextResult
{
    public List<NewsInfo> List { get; set; }

    public override TuLingResult ToTuLingResult(string fromUserName, string toUserName)
    {
        if (List.Count > 10)
        {
            List = List.Take(10).ToList();
        }

        return new TuLingResult
        {
            DataType = typeof(NewsMsg),
            Data = new NewsMsg
            {
                FromUserName = fromUserName,
                ToUserName = toUserName,
                ArticleCount = List.Count,
                Articles = List.Select(m => new MsgNewsInfo
                {
                    Title = m.Article,
                    Description = m.Source,
                    Url = m.DetailUrl,
                    PicUrl = m.Icon
                }).ToList(),
                CreateTime = UnixTimestamp.Now.ToNumeric(),
                MsgType=MsgType.News
            }
        };
    }
}

public class NewsInfo
{
    /// <summary>
    /// 標題
    /// </summary>
    public string Article { get; set; }

    /// <summary>
    /// 來源
    /// </summary>
    public string Source { get; set; }

    /// <summary>
    /// 詳情地址
    /// </summary>
    public string DetailUrl { get; set; }

    /// <summary>
    /// 圖標地址
    /// </summary>
    public string Icon { get; set; }
}

 同理創建圖靈機器人提供的各類數據實體類

我們想要支持的數據實體都定義完畢後,我們便可以開始請求圖靈接口,獲取真實的消息了,在此我們使用HttpClient實現。

private const string TULING_API_URL = "http://www.tuling123.com/openapi/api";
private const string TULING_API_KEY = "XXXXX";//圖靈的APIKEY
public TuLingResult GetMsgFromResponse(string keyword, string userFlag, string efhName)
{
    string linkString = string.Format("{0}?key={1}&info={2}&userid={3}"
        , TULING_API_URL, TULING_API_KEY, keyword, userFlag);

    string content = string.Empty;
    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = client.GetAsync(linkString).Result;

        content = response.Content.ReadAsStringAsync().Result;
        logger.DebugFormat("圖靈機器人響應:{0}", content);
    }
    return ConvertToMsg(content, userFlag, efhName);
}

 圖靈返回了code標識消息的類型和錯誤信息,因此我們先將響應消息解析爲TextResult,拿到圖靈的類型。

先定義圖靈類型枚舉

public enum ResultType
{
    TL_FORMAT_DATA = 50000,
    TL_TEXT_DATA = 100000,
    TL_LINK_DATA = 200000,
    TL_NOVEL_DATA = 301000,
    TL_NEWS_DATA = 302000,
    TL_APP_DATA = 304000,
    TL_TRAIN_DATA = 305000,
    TL_AIRPORT_DATA = 306000,
    TL_TUAN_DATA = 307000,
    TL_TUWEN_DATA = 308000,
    TL_HOTEL_DATA = 309000,
    TL_LOTTERY_DATA = 310000,
    TL_PRICE_DATA = 311000,
    TL_RESTAURANT_DATA = 312000,

    TL_ERROR_LENGTH = 40001,
    TL_ERROR_EMPTY = 40002,
    TL_ERROR_INVALID = 40003,
    TL_ERROR_OUTLIMIT = 40004,
    TL_ERROR_NOTSUPPORT = 40005,
    TL_ERROR_SERVERUPDATE = 40006,
    TL_ERROR_SERVERERROR = 40007
}

 對應於圖靈的返回碼

100000  文本類數據
200000  網址類數據
301000  小說
302000  新聞
304000  應用、軟件、下載
305000  列車
306000  航班
307000  團購
308000  優惠
309000  酒店
310000  彩票
311000  價格
312000  餐廳
40001   key的長度錯誤(32位)
40002   請求內容爲空
40003   key錯誤或帳號未激活
40004   當天請求次數已用完
40005   暫不支持該功能
40006   服務器升級中
40007   服務器數據格式異常
50000   機器人設定的“學用戶說話”或者“默認回答” 

 而後拿到消息類型

private ResultType GetResultType(string response)
{
    var result = JsonConvert.DeserializeObject<TextResult>(response);

    return (ResultType)result.Code;
}

 之後,我們便可以按照不同類型返回相對應的TuLingResult。

public TuLingResult ConvertToMsg(string response, string userFlag, string efhName)
{
    IResponse result = null;

    var resultType = GetResultType(response);

    switch (resultType)
    {
        case ResultType.TL_TEXT_DATA:
            result = JsonConvert.DeserializeObject<TextResult>(response);
            break;

        case ResultType.TL_LINK_DATA:
            result = JsonConvert.DeserializeObject<LinkResult>(response);
            break;

        case ResultType.TL_NEWS_DATA:
            result = JsonConvert.DeserializeObject<NewsResult>(response);
            break;

        case ResultType.TL_TUWEN_DATA:
            result = JsonConvert.DeserializeObject<TuWenResult>(response);
            break;

        case ResultType.TL_TRAIN_DATA:
            result = JsonConvert.DeserializeObject<TrainResult>(response);
            break;

        case ResultType.TL_AIRPORT_DATA:
            result = JsonConvert.DeserializeObject<AirportResult>(response);
            break;

        case ResultType.TL_APP_DATA:
            result = JsonConvert.DeserializeObject<AppResult>(response);
            break;

        case ResultType.TL_HOTEL_DATA:
            result = JsonConvert.DeserializeObject<HotelResult>(response);
            break;

        case ResultType.TL_PRICE_DATA:
            result = JsonConvert.DeserializeObject<PriceResult>(response);
            break;

        case ResultType.TL_ERROR_LENGTH:
        case ResultType.TL_ERROR_INVALID:
        case ResultType.TL_ERROR_EMPTY:
        case ResultType.TL_ERROR_OUTLIMIT:
            result = new TextResult { Text = "您的輸入有誤" };
            break;

        case ResultType.TL_ERROR_SERVERERROR:
        case ResultType.TL_ERROR_SERVERUPDATE:
            result = new TextResult { Text = "服務器忙,暫時無法爲您提供服務" };
            break;

        case ResultType.TL_ERROR_NOTSUPPORT:
            result = new TextResult { Text = "俺還小,您說的這個還得慢慢學習,以後再來試吧" };
            break;

        default:
            result = new TextResult { Text = "俺還小,不知道你在說啥子(⊙_⊙)?" };
            break;
    }

    return result.ToTuLingResult(efhName, userFlag);
}

 而後,我們便可以將我們拿到的TuLingResult中的Data序列化爲微信需要的XML

var requestResult = TuLingService.Instance.GetMsgFromResponse(content, userName, efhName);

responseContent = MsgService.Instance.ResponseXML(requestResult.Data, requestResult.DataType);
return new HttpResponseMessage(HttpStatusCode.OK)
{
    Content = new StringContent(responseContent, Encoding.UTF8, "application/xml"),
};

 至此,我們的微信公衆號調用圖靈機器人接口就搞定了!


源碼託管在csdn上,歡迎批評指正。 https://code.csdn.net/yanhuiqiang/efh-blog

原文鏈接:http://efenghuo.com/blog/2499.aspx

發佈了192 篇原創文章 · 獲贊 30 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章