当微软牛津计划遇到微信App ——微信实现部分

2023-12-30 20:40

本文主要是介绍当微软牛津计划遇到微信App ——微信实现部分,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:王豫翔,微软连续多年多个方向的MVP,目前主要关注大数据、云技术和人工智能。在编程道路上遵循自己的“三少”“三多”原则:少讨论概念,少争论特征、少议论模型;多写代码、多做测试、多做应用。
本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅2016年《程序员》

微软牛津计划(Project Oxford)提供了一系列机器学习API,包含计算机视觉、语音识别和语言理解等认知服务,它能为微信开发带来怎样有趣的功能?请看本文分解。

微软牛津计划提供了一组基于Rest架构的API和SDK工具包,帮助开发者轻轻松松使用微软的自然数据理解能力为自己的解决方案增加智能服务。利用微软牛津计划构建你自己的解决方案,支持任意语言及任意开发平台。主要提供了四个自然语言处理方面的核心问题解决方案:人脸识别、语音识别、计算机视觉,以及语言理解智能服务。

图片描述

图1 应用界面

微软提供了这么强大的API,我第一时间就想,是不是可以迁移到微信平台上去做一些好玩的应用,不过在这之前,我没有做过任何微信开发的工作,所以本篇文章将分享整个实现的经验。

ASP.NET WebAPI实现微信接入验证

首先你需要一个微信公众号,很重要的是你需要完成认证,这点非常重要。当你完成公众号的基本设定后,我们需要为开发做第一件事情:让微信验证通过开发者中心页配置的服务器地址。微信服务器将发送GET请求到我们注册的服务器地址URL上,GET请求携带四个参数:signature、timestamp、nonce、echostr。我们编写了一个WebAPI对微信的请求进行反馈。

public HttpResponseMessage Get(string signature, string timestamp, string nonce, string echostr)
{string[] ArrTmp = { TOKEN, timestamp, nonce };Array.Sort(ArrTmp);string tmpStr = string.Join("", ArrTmp);var result = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1").ToLower();return new HttpResponseMessage (){ Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/x-www-form-urlencoded") };
}

上面这段代码的要点是返回值,很多工程师在使用WebAPI返回给微信验证时一直失败,是因为忽略了返回值的编码要求是application/x-www-form-urlencoded。

ASP.NET WebAPI实现微信JS-SDK接口注入权限验证配置

我们的客户端采用微信的JS-SDK,但是所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用,当使用JS-SDK的时候,微信会将appId、timestamp、nonceStr和signature的参数进行加密和验算是否正确,所以我们需要提供一个正确的签名值。需要获得这个签名必须要完成两步,图2所示的UML描述了这个过程。

图片描述

图2 获取签名过程示意图

第一步:获取Access Token

if (HttpRuntime.Cache["access_token"] == null)
{var queryString = HttpUtility.ParseQueryString(string.Empty);queryString["grant_type"] = "client_credential";queryString["appid"] = APPID;queryString["secret"] = APPSECRET;var uri = "https://api.weixin.qq.com/cgi-bin/token?" + queryString;HttpResponseMessage response;response = await client.GetAsync(uri);var msg = await response.Content.ReadAsStringAsync();var jsonobj = Newtonsoft.Json.Linq.JObject.Parse(msg);HttpRuntime.Cache.Add("access_token",(string)jsonobj["access_token"],null,DateTime.Now.AddMinutes((int)jsonobj["expires_in"]),new TimeSpan(0, 0, 0),System.Web.Caching.CacheItemPriority.AboveNormal,null);
}

第二步:获取jsapi_ticket。

if (HttpRuntime.Cache["jsapi_ticket"] == null)
{var queryString = HttpUtility.ParseQueryString(string.Empty);queryString["access_token"] = (string)HttpRuntime.Cache["access_token"];queryString["type"] = "jsapi";var uri = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?" + queryString;HttpResponseMessage response;response = await client.GetAsync(uri);var msg = await response.Content.ReadAsStringAsync();var jsonobj = Newtonsoft.Json.Linq.JObject.Parse(msg);HttpRuntime.Cache.Add("jsapi_ticket",(string)jsonobj["ticket"],null,DateTime.Now.AddMinutes((int)jsonobj["expires_in"]), new TimeSpan(0, 0, 0), System.Web.Caching.CacheItemPriority.AboveNormal, null);
}

我们用于签名的素材都到齐了,我们要实现签名算法了。实现的代码如下。

var pwd = string.Format("jsapi_ticket={0}&noncestr={1}×tamp={2}&url={3}",(string)HttpRuntime.Cache["jsapi_ticket"],noncestr,timestamp,url);var tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(pwd, "SHA1");return Request.CreateResponse(HttpStatusCode.OK, tmpStr);

这时候我们前端的HTML5就可以正确的采用JS-SDK了。

ASP.NET获取微信客户端上传的图片

本来我以为这是个很简单的事情,后来才发现,使用微信JS-SDK的时候,微信的HTML5客户端不会将图片直接POST给我的服务端,而是先提交给微信服务器,然后我的服务端需要通过serverId 来获得图片,大致的流程我绘制了UML,见图3,大家可以理解下。

图片描述

图3 获取微信客户端上传图片的过程

目前我们只关心服务器这段,我们将得到客户端传来的serverID,从微信的服务器上下载图片到本地。我们实现的代码如下。

public async Task<string> Get(string mediaid)
{var queryString = HttpUtility.ParseQueryString(string.Empty);queryString["access_token"] = await Get();queryString["media_id"] = mediaid;var uri = "http://file.api.weixin.qq.com/cgi-bin/media/get?" + queryString;HttpResponseMessage response;response = await client.GetAsync(uri);var msg = await response.Content.ReadAsStreamAsync();var file = response.Content.Headers.ContentDisposition.FileName.Replace("\"", "");var helper = new ProjecToxfordClientHelper();var content = await FileHelper.ReadAsync (msg);FileHelper.SaveFile(content, file);return file;
}</string>

好了,到了现在,我们对微信服务器需要实现的接口都差不多了,接下来就可以设计微信的客户端了。

WeUI设计微信客户端首页样式

WeUI是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信网页开发量身设计,可以令用户的使用感知更加统一。在微信网页开发中使用 WeUI,有如下优势:

  • 同微信客户端一致的视觉效果,令所有微信用户都能更容易地使用你的网站;
  • 便捷获取快速使用,降低开发和设计成本;
  • 微信设计团队精心打造,清晰明确,简洁大方。

该样式库目前包含button、cell、dialog、progress、toast、article、icon等各式元素,我们可以在https://github.com/weui/weui获得源代码和DEMO。

我们先做首页,以了解WeUI样式库的使用方式。

建立Index.html引入样式库和配置head节点。

<meta charset="utf-8">
<title>脸探</title>
<meta name="viewport" content="initial-scale=1.0,user- scalable=no,maximum- scale=1,width=device-width"> <link href="css/weui.css" rel="stylesheet"><link href="css/example.css" rel="stylesheet">

Body节点下的直接子元素是< div class=”page”>,其他所有元素都在这个节点下,我们的Index.html页面设计了两个div元素分别是:

<div class="hd">
<div class="bd"></div></div>

hd节点下的代码非常简单,就是title的描述。

<h1 class="page_title">脸探</h1>
<p class="page_desc">测测脸的相似度</p>

bd包含的是一个< div class=”weui_panel weui_panel_access”>,WeUI提供的Panel非常容易设计图文组合列表,WeUI提供了一系列很有用的类:weui_panel、weui_panel_access、weui_panel_hd、weui_panel_bd。

我们的Panel的标题就可以用weui_panel_hd进行修饰。

<div class="weui_panel_hd"></div>

具体的内容可以被weui_panel_bd修饰。

<div class="weui_panel_bd"></div>

weui_panel_bd 的子元素如下:

<a href="" class=" weui_media_box weui_media_appmsg "><div class=" weui_media_hd"><imgsrc="img 4432144_111855038929_2.jpg"="" alt=""></imgsrc="img></div><div class=" weui_media_bd"><h4 class=" weui_media_title ">标题</h4><p class="weui_grid_label">内容 </p></div>  
</a>

了解了如何布局一个列表项,那首页就容易完成了,代码如下。

<div class="page"><div class="hd"><h1 class="page_title">脸探</h1><p class="page_desc">测测脸的相似度</p></div><div class="bd"><div class="weui_panel weui_panel_access"><div class="weui_panel_hd">娃像谁     </div><div class="weui_panel_bd"><a href="family.html" class="weui_media_box weui_media_appmsg"><div class="weui_media_hd"><img class="weui_media_appmsg_thumb" src="fonts/family.jpg" alt=""></div><div class="weui_media_bd"><h4 class="weui_media_title">三人照</h4><p class="weui_media_desc">上传一家三口三人照,立即知道孩子与父母相像指数</p></div></a><a href="family3.html" class="weui_media_box weui_media_appmsg"><div class="weui_media_hd"><img class="weui_media_appmsg_thumb" src="fonts/one.jpg" alt=""></div><div class="weui_media_bd"><h4 class="weui_media_title">单人照</h4><p class="weui_media_desc">上传一家三口各自照片,立即知道孩子与父母相像指数</p></div></a></div></div></div><div class="bd"><div class="weui_panel weui_panel_access"><div class="weui_panel_hd">夫妻相    </div><div class="weui_panel_bd"><a href="couple2.html" class="weui_media_box weui_media_appmsg">  <div class="weui_media_hd"><img class="weui_media_appmsg_thumb" src="fonts/couple.jpg" alt=""></div><div class="weui_media_bd"><h4 class="weui_media_title">双人照</h4><p class="weui_media_desc">上传你和TA的双人照,你立即知道你们的天生缘分指数</p></div></a><a href="couple.html" class="weui_media_box weui_media_appmsg"><div class="weui_media_hd"><img class="weui_media_appmsg_thumb" src="fonts/one.jpg" alt=""></div><div class="weui_media_bd"><h4 class="weui_media_title">单人照</h4><p class="weui_media_desc">上传你们两人各自照片,你立即知道你们的天生缘分指数</p></div></a></div></div></div>
</div>

我们得到的首页效果大致如图4所示。

图片描述

图4 微信客户端首页效果图

设计微信客户端功能页样式

以娃像谁-单人照的页面为例,页面代码如下。

<div class="pic_panel"><div class="parent" id="parent1"><i class="icon iconfont icon-210 human"></i></div><div class="parent" id="parent2"><i class="icon iconfont icon-nv human"></i></div><div class="clear"></div><div class="parent1like like"></div><div class="parent2like like"></div><div class="clear"></div><div class="picture" id="child"><i class="icon iconfont icon-child human"></i></div><form><input type="button" class="next" id="uploadImage" value="GO !!!"></form>
</div>

id=”parent1” 和 id=”parent2” 为存放父母照片的容器,id=”child”为存放孩子照片的容器,点击容器触发选择照片,选择完成点击按钮作比较。class=”parent1like”和class=”parent2like” 分别显示 id=”child”分别与id=”parent1”和id=”parent2” 对比的结果。

我们得到的页面效果类似图5所示的样子。

图片描述

图5 娃像谁—单人照的页面效果图

实现微信客户端交互

在之前我们写了一个WebAPI接口来实现微信JS-SDK接口注入权限验证配置,现在我们的客户端需要调用这个接口来做验证了。客户端你需要引用jweixin-1.0.0.js。

只要我们的业务需要使用微信JS-SDK,则都需要完成接口注入的权限验证,验证的方式我们来一步步分析见图6。

图片描述

图6 JS-SDK接口注入的权限验证过程

页面将noncestr(这个可以是页面定义一个常数)、timestamp(其实也可以是常数)、url当前页面地址提交给我们最早写的/api/weixin接口,然后将返回的签名提交给wx.config即可。下面的代码可以作为你的模板使用。

$(function () {var timestamp = Date.parse(new Date())/1000;var localurl = encodeURIComponent(window.location.href.split('#')[0]);$.ajax({url: 'http://www.********.cn/wxapi/api/weixin',dataType: "json",data: {noncestr: 'FFUmZdbWVT9mVP7a',timestamp: timestamp,url: window.location.href.split('#')[0]
},success: function (data) {
wxFace(data.toLowerCase());}})
function wxFace(signature) {wx.config({debug: false,appId: 'wxec54ec7f720993da',timestamp: timestamp,nonceStr: 'FFUmZdbWVT9mVP7a',signature: signature,jsApiList: ['checkJsApi','onMenuShareTimeline','onMenuShareAppMessage','chooseImage','previewImage','uploadImage','downloadImage']            });}});

然后我们定义选择图片函数,当选择id=”parent1”、 id=”parent2”、id=”child”时调用。

function chooseUpload(selector) {wx.chooseImage({success: function (res) {$("#loading").show();$(function () {$.each(res.localIds, function (i, n) {wx.uploadImage({localId: res.localIds.toString(), // 需要上传的图片的本地ID,由chooseImage接口获得                        isShowProgressTips: 0, // 默认为1,显示进度提示success: function (res1) {$.ajax({url: 'http://www.******.cn/wxapi/face/detect/' + res1.serverId,                                   dataType: "json",success: function (data) {$("#loading").hide(); if (JSON.parse(data).length == 1) { $(selector).html('<img src="' + n + '"> <br>')                                          .data('faceId', JSON.parse(data)[0].faceId);} else if (JSON.parse(data).length > 1) { alert('请选择单人照哦')} else { alert('啊,我看不到你的脸~')}}})},fail: function (res) {alert(JSON.stringify(res));}});});});}});
}

触发点击事件调用上传图片函数。

document.querySelector('#parent1').onclick = function () {chooseUpload('#parent1')
};
定义函数,将拿到的两张照片的id做对比。function verify(selector, parent, child) {$("#loading").show();$.ajax({url: 'http://www.******.cn/wxapi/face/verify/' + parent + '/' + child,    dataType: "json",success: function (data) {$("#loading").hide();$(selector).html('相似度:' + (JSON.parse(data).confidence * 100).toFixed(2) + '%')}})      }

最后是我们分享朋友圈的功能实现。

var shareData = {title: '测测孩子跟谁像',//分享的标题desc: '来看看孩子跟爸爸比较像还是跟妈妈比较像',//分享的描述link: window.location.href,//分享的快照imgUrl: 'http://www. .******.cn/WeFace/fonts/family.jpg'//分享的链接};wx.onMenuShareAppMessage(shareData);wx.onMenuShareTimeline(shareData);

分享结果如图7所示。

图片描述

图7 朋友圈分享功能效果图

总结

本文主要针对如何使用APS.NET WebAPI实现微信注入进行了深入讲解。下期会承接本文,重点分享服务的实现过程,内容主要有:调用封装微软牛津计划API、使用MongoDB存储数据和客户端如何使用。全文阅读完毕后,你将可以自己去编写更有价值的应用了。


订阅2016年程序员(含iOS、Android及印刷版)请访问 http://dingyue.programmer.com.cn
图片描述

订阅咨询:

• 在线咨询(QQ):2251809102
• 电话咨询:010-64351436
• 更多消息,欢迎关注“程序员编辑部”

这篇关于当微软牛津计划遇到微信App ——微信实现部分的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/553944

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import