用 Rails 搭建微信公众平台 API

2019-03-02 00:44|来源: 网路

最近微信很火,春节在家抽空研究了公众平台的 API ,发现挺有意思的,写篇小文,简单记录一下

微信 API 简介

先来看看 API 的工作流程和机制
微信公众平台的账户可以开启“开发模式”(在“高级功能”中),开启之后,用户发送微信到你的账户时,将有如下流程

用户向公众平台账号发送微信后,微信服务器会将一段 XML 以 HTTP POST 请求的方式发送给你的 API 服务器
API 服务器经过处理后,通过 HTTP 响应将另一段 XML 返回给微信服务器,这时候用户会收到来自你的公众平台帐号的回复

那么,两个服务器之间如何互相验证身份呢?
在开启开发模式时,除了要填写 API 服务器的 URL,还要填写一个 token 值
填写完毕后,微信服务器会发送一个 GET 请求给 URL ,附带一些参数,你可以根据 token 与参数校验合法性,合法时需要根据要求返回一个字符串,这样微信服务器才会确认你的 API 服务器的身份
以后每次微信服务器 POST 请求时,都会带上这些参数,你可以以同样的方式来判断对方的合法性

具体的细节,可以参照官方文档 http://mp.weixin.qq.com/wiki/index.php
XML 传输格式之类细节的本文就不再赘述了,文档上说的很详细。假如你已经大致了解这些内容,那么可以进入下一节

搭建服务

根据以上的原理,我们的服务需要提供两个 HTTP 接口,一个用于初始化时验证,另一个用来收发消息
新建一个 Rails 工程,然后创建一个 Controller ,并配置 routes

class WeixinsController < ApplicationController
  skip_before_filter :verify_authenticity_token
  def show
  end

  def create
  end
end

# routes.rb
resource :weixin

这里需要跳过验证 CSRF token 的 filter ,否则微信服务器 POST 过来的消息会被拦截掉
鉴于两个 action 都需要同样的验证逻辑,我们可以把验证的过程写在 filter 方法里

before_filter :check_weixin_legality

  private
  def check_weixin_legality
    array = [Rails.configuration.weixin_token, params[:timestamp], params[:nonce]].sort
    render :text => "Forbidden", :status => 403 if params[:signature] != Digest::SHA1.hexdigest(array.join)
  end

 

这里为了方便,将 token 写在了 Rails 的 config 配置里
然后根据文档的要求,补全第一个 action,返回参数上的 echostr

def show
    render :text => params[:echostr]
  end

下面处理核心的收发消息 action
首先是接收,根据文档,微信服务器发送过来的是 XML ,幸运的是 Rails3 已经内置了相应的解析功能,非常方便
比如如果服务器 POST 发送以下的 XML

<xml>
 <ToUserName><![CDATA[toUser]]></ToUserName>
 <FromUserName><![CDATA[fromUser]]></FromUserName> 
 <CreateTime>1348831860</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[this is a test]]></Content>
 <MsgId>1234567890123456</MsgId>
</xml>

在 Controller 中,可以直接使用 params 参数取值,跟处理表单提交参数一样,比如params[:xml][:MsgType] == "text"

那么发送 XML 格式的响应该怎么实现呢?最简单的方法,用不着乱七八糟的 XML 库,直接用 erb 就行了

  def create
    if params[:xml][:MsgType] == "text"
      render "echo", :formats => :xml
    end
  end
# echo.xml.erb
<xml>
    <ToUserName><![CDATA[<%= params[:xml][:FromUserName] %>]]></ToUserName>
    <FromUserName><![CDATA[<%= params[:xml][:ToUserName] %>]]></FromUserName>
    <CreateTime><%= Time.now.to_i %></CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[大山的回声:<%= params[:xml][:Content] %>]]></Content>
    <FuncFlag>0</FuncFlag>
</xml>

甚至可以引入 layout,因为除了 MsgType 和 Content 两个节点之外,其他部分基本都是固定的

OK,到这里,通过不足50行代码,我们已经成功搭建了一个简单的“回声”微信 API ,Rails 的快速、强大表现得淋漓极致!

最后,微信要求 API 必须部署在 80 端口,如果没有自己的服务器,推荐部署到国外免费的 PAAS 平台上
比如 CloudFoundry 就相当不错,空间免费,提供二级域名,只需要几行命令就可以将 Rails 程序发布上去

QQ 表情是通过 /:,@! 这样的形式来发送,资深的 QQ 用户应该都知道
符号表情其实是特殊的 UTF8 字符,比如 \u{1F389} 这个字符就是上图中的喇叭
关于符号表情,可以点这里了解 http://www.iapps.im/wp-content/uploads/2012/02/emoji-pinyin.png
下面就是上图中表情的代码

<Content><![CDATA[/:,@! /::)/::~<%= "\u{1F389}" %><%= "\u{1F47B}" %>]]></Content>

因为是写在 CDATA 中,所以没法用 &#x1F389 这样的形式直接写 UTF8 字符,只能通过 erb 来输出

新用户关注时自动回复

新用户关注你的公众帐号时,微信服务器会发一条特殊的文本信息给 API 服务器,内容为 “Hello2BizUser"
这样我们可以根据这条消息来回复相应的欢迎信息

FuncFlag 的作用

XML 回复中有一个 FuncFlag 节点,通过设置这个节点的内容,可以给微信消息加星标
比如用户如果发送一个请求,而 API 又无法处理,可以将这个节点内容设置为 1,那么用户发送的消息会被加上星标
这样以后在公众平台的后台就可以方便地找到这条消息

其他技巧

之前用 Rails 弄过微信 API,无比轻松,几十行代码就能搭建一个简单的接口
不过要折腾得大一点的时候,发现代码组织上会比较麻烦,比如接口要实现这样的功能:如果发送 @+字符串,返回消息A,如果发送图片,返回消息B,发送其他文本,返回消息C,这时候代码可能会这样

def create
    query_type = params[:xml][:MsgType]
    if query_type == "image"
        do_method_b
    elsif query_type == "text"
        query = params[:xml][:Content]
        if query.start_with? "@"
            do_method_a
        else
            do_method_c
        end
    end
end

可以看到大量的逻辑堆在一个方法里面,即便用子方法切开,看起来也很乱。如果能够像 route 一样,根据请求的不同,由不同的 Controller 来处理的话,代码会清晰很多。我翻了下 route 的 API,发现还真能这样做,constraints 参数可以根据 request 的不同来决定路由

  scope :path => "/weixin", :via => :post do
    root :to => 'weixin#method_a', :constraints => lambda { |request| request.params[:xml][:MsgType] == 'image' }

    root :to => 'weixin#method_b', :constraints => lambda { |request| request.params[:xml][:MsgType] == 'text' && request.params[:xml][:Content].start_with?('@') }

    root :to => 'weixin#method_c', :constraints => lambda { |request| request.params[:xml][:MsgType] == 'text' }
  end

这样看上去就清晰多了,如果嫌后面的 lambda 还是太繁琐,可以用一个 class 再稍微封装一下,比如我现在封装后的代码是这样

  scope :path => "/weixin", :via => :post do
    root :to => 'weixin#method_a', :constraints => Weixin::Router.new(:type => "image")

    root :to => 'weixin#method_b', :constraints => Weixin::Router.new(:type => "text", :content => /^@/)

    root :to => 'weixin#method_c', :constraints => Weixin::Router.new(:type => "text")
  end

共同折腾微信 API 的同志们可以参考下


转自:http://www.cnblogs.com/zkblogs/articles/3092159

相关问答

更多
  • 先用抓包软件抓下登录时的数据包,然后 分析他用的是什么协议,然后 根据他的协议来写自己的程序,不过这个是一个比较大的工作量大事。不比抢票软件简单
  • 能使用的!微信 在安卓手机里可以使用,安装是用java 开发的,所以 可以用java开发
  • 擦, 我正要实现这个功能呢 都有源代码了啊 查看原帖>>
  • 微信公众平台开发注意事项: 一、微信公众平台开发是指为微信公众号进行业务开发,为移动应用、PC端网站、公众号第三方平台(为各行各业公众号运营者提供服务)的开发,请前往微信开放平台接入。 二、在申请到认证公众号之前,你可以先通过测试号申请系统,快速申请一个接口测试号,立即开始接口测试开发。 三、在开发过程中,可以使用接口调试工具来在线调试某些接口。 四、每个接口都有每日接口调用频次限制,可以在公众平台官网-开发者中心处查看具体频次。 五、在开发出现问题时,可以通过接口调用的返回码,以及报警排查指引(在公众平台 ...
  • 小猪cms还凑合,,有源码的 ,每周更新两三个模板的 ,你可以看下 ,,
  • 微网站开发模式教程:   第一步:申请消息接口   在公众平台网站的高级功能 – 开发模式页,点击“成为开发者”按钮,填写URL和Token,其中URL是开发者用来接收微信服务器数据的接口URL。Token可由开发者可以任意填写,用作生成签名。   第二步:验证URL有效性   开发者提交信息后,微信服务器将发送GET请求到填写的URL上,GET请求携带四个参数:   开发者通过检验signature对请求进行校验。若确认此次GET请求来自微信服务器,请原样返回 echostr参数内容,则接入生效,成为开发 ...
  • API接口开发,需要懂代码才可以,实在不会可以问问该亚微天下。
  • 刚刚看错了 这个在原理上是可以实现的 但是电话号码除外 这个需要关注的人自己提供给公众号才行
  • 这个需要根据你找什么样的开发商,然后开发什么样的功能,如果是该需要对接你们系统之类的功能比较复杂,有几千的,也有好几万的,这个看你的需求
  • 登录你的微信平台,点击“公众号设置”。 点击“功能设置”,然后点击“设置”。 设置JS接口安全域名。这里填写的是一级域名,不带www和http。最多可以设置三个域名。设置完后点击确定。(多说一句,相比以前的分享没有任何域名限制,这里设置安全域名,目的是为了当发现此公众平台发现诱导分享行为时,可以根据此域名追溯到所有分享出去的链接,以及通过这些链接增加的粉丝。这样,微信就可以牢牢控制了你的微信平台,一旦发现违规,让分享链接失效,删除掉诱导行为增加的粉丝,是瞬间就可以完成的。因此,微信平台的开发者,一定要合理来 ...