用 Rails 搭建微信公众平台 API

最近微信很火,春节在家抽空研究了公众平台的 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
2019-03-02 00:44

知识点

相关教程

更多

Rails4 已经移出了params可以解析xml的功能,拿rails4做微信API的童鞋们注意了

拜读了用 Rails 搭建微信公众平台 API之后发现,params[:xml]这个办法在Rails 4里面已经被办掉了,于是就看了一下Rails 4的新特性发现XML Parameter parsing has been sent to a plugin. 于是就去找这个plugin了,在Github上,地址是https://github.com/rails/actionpack-xml_par

顶 使用Rails plugin weixin_rails_middleware 快速搭建微信营销平台

weixin_rails_middleware,是专门为Rails项目开发微信第三方营销平台的gem,此gem已经在公司内部使用, Github链接:https://github.com/lanrion/weixin_rails_middleware Github example:https://github.com/lanrion/weixin_rails_middleware_example

微信公众平台API分析

大家都知道微信哈,但是不一定所有的人都玩过微信公众平台,因为公司在弄的原因,我最近两个月也在兼做这一个项目。 公司希望有一个微信公众账户,能对自己产品做到一定的推广作用。可是腾讯自己提供了官方的规则编辑很不好用并且还有限制,不如规则只能小于等于50条这样的。所以市场部门那边请我帮忙他们写一个后台将公众平台切换到开发模式中,今后只与我做的后台做交互; 进入到开发模式中可以阅读到官方文档http://

自制公众平台Web Api(微信)

最近一段时间感觉没什么东西可以分享给大家,又由于手上项目比较赶,不太更新博客了,今天趁着生病闲下来的时间分享一些项目中的东西给大家。   公众平台  提起公众平台当下最流行的莫过于腾讯的微信了,当然还有易信等公众平台,每个公众平台都提供了一些API接口供开发者进行二次开发,当然肯定不是这些所有的API都是我们需要的也当然不是所有的功能都是能通过这些API可以实现的,所以抱着这个问题我自己写了一些常

分享一个免费的聊天api

很多人都接触过微信公众平台的开发,很多微信公众帐号都希望能实现智能交互聊天的效果,但是这件事对于我们普通的开发者来说,几乎是不可能实现的。遇到这种问题很自然的会去网上找一下有没有现成的智能聊天api接口之类的资源,下面就给大家介绍一个我用过的聊天机器人接口,先上代码。  public class RobortDemo {  /** 调用图灵机器人平台接口*/ public static voidm

微信API 引用

最近一直在调用微信的API,却发现一直调用不成功,纠结了好久,各方面找教程,现在晒出来和大家分享一下               最近一直在调用微信的API,却发现一直调用不成功,纠结了好久,各方面找教程,找官方,官方里的文档也只是写得很模糊,说是按三步走。  1、申请App_ID  2、填写包名3、  获取程序签名的md5值,  这三步只要你走对了就能调通,可是大家都不知道有时候我们打包的key

微信公众平台通用接口API指南

下述文档已过期,新版文档请访问http://www.cnblogs.com/txw1958/p/weixin-access-token.html 微信公众平台目前分成消息接口和通用接口两大模块。 接入消息接口的微信公众账号,当关注该公众账号的粉丝向其发送消息,微信服务器会对公众账号所对应的服务器地址推送一个特定结构的消息体,公众账号开发者可以通过响应包进行对该条消息的回复。 通用接口的作用是实现诸

微信公众平台消息接口API指南

下述文档已过期,更加完整及详细的请访问 http://www.cnblogs.com/txw1958/p/wechat-tutorial.html 简介  微信公众平台消息接口为开发者提供了一种新的消息处理方式。微信公众平台消息接口为开发者提供与用户进行消息交互的能力。对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使用http请求对接入的网址进行消息推送,第三方服务

微信公众平台消息接口API指南

简介  微信公众平台消息接口为开发者提供了一种新的消息处理方式。微信公众平台消息接口为开发者提供与用户进行消息交互的能力。对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使用http请求对接入的网址进行消息推送,第三方服务器可通过响应包回复特定结构,从而达到回复消息的目的。 申请消息接口  点击申请,填写网址url和token,其中token可由开发者可以任意填写,用

全文检索(SOLR)前端应用浅析续 Rails前端分析

前两篇对Lucid的应用和SOLR的核心扩展简要进行了介绍,现在简要看一下基于SOLR的基础上展现给前端的界面如何做,这个部分Lucid提供了源代码,因此看起来更方便一下。 上两个文章的内容如下: 全文检索(SOLR)前端应用浅析http://www.cnblogs.com/2018/archive/2011/07/29/2121519.html 全文检索(SOLR)前端应用浅析续 LWE-COR

微信公众开发api接口

简介    微信公众平台消息接口为开发者提供了一种新的消息处理方式。微信公众平台消息接口为开发者提供与用户进行消息交互的能力。对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使用http请求对接入的网址进行消息推送,第三方服务器可通过响应包回复特定结构,从而达到回复消息的目的。 申请消息接口    点击申请,填写网址url和token,其中token可由开发者可以任意

api无限拓展的想像世界

2013-06-12 16:12        API无限拓展的想像世界 互联网的世界是开放的世界,就是封闭如苹果,也不得不在app store引进开发者,共同打造丰富应用的 apple app。更不用说骨子里透着开放基因的google。google所有的产品都提供着标准的API,最大限度放开权限把应用的想像空间放给广大开发者。facebook,twitter等等新兴互联网公司更是把一切都API化

微信公众平台自定义菜单接口API指南

微信公众平台开发模式自定义菜单接口API指南  开发实现方法,请查看 微信公众平台开发(58)自定义菜单  简介  开发者获取使用凭证(如何获取凭证)后,可以使用该凭证对公众账号的自定义菜单进行创建、查询和删除等操作。 自定义菜单接口可实现以下类型按钮: click(点击事件): 用户点击click类型按钮后,微信服务器会通过消息接口(event类型)推送点击事件给开发者,并且带上按钮中开发者填写

rails 单元测试

rails 如何保证每次单元测试都清理上一个测试的数据。

荐 微信公众平台私有API, 得到用户fakeId

-------最新内容--------------------  本程序已复活, 多谢forecho(他的github:https://github.com/forecho)维护 ---------以下内容时间久远--------------- 最新在工作之余玩起了微信公众平台, 并且快速做了一个玩骰子的小游戏(公共微信号cometoplay), 因为这个游戏需要主动发送信息给用户, 所以需要用到

最新教程

更多

java线程状态详解(6种)

java线程类为:java.lang.Thread,其实现java.lang.Runnable接口。 线程在运行过程中有6种状态,分别如下: NEW:初始状态,线程被构建,但是还没有调用start()方法 RUNNABLE:运行状态,Java线程将操作系统中的就绪和运行两种状态统称为“运行状态” BLOCK:阻塞状态,表示线程阻塞

redis从库只读设置-redis集群管理

默认情况下redis数据库充当slave角色时是只读的不能进行写操作,如果写入,会提示以下错误:READONLY You can't write against a read only slave.  127.0.0.1:6382> set k3 111  (error) READONLY You can't write against a read only slave. 如果你要开启从库

Netty环境配置

netty是一个java事件驱动的网络通信框架,也就是一个jar包,只要在项目里引用即可。

Netty基于流的传输处理

​在TCP/IP的基于流的传输中,接收的数据被存储到套接字接收缓冲器中。不幸的是,基于流的传输的缓冲器不是分组的队列,而是字节的队列。 这意味着,即使将两个消息作为两个独立的数据包发送,操作系统也不会将它们视为两个消息,而只是一组字节(有点悲剧)。 因此,不能保证读的是您在远程定入的行数据

Netty入门实例-使用POJO代替ByteBuf

使用TIME协议的客户端和服务器示例,让它们使用POJO来代替原来的ByteBuf。

Netty入门实例-时间服务器

Netty中服务器和客户端之间最大的和唯一的区别是使用了不同的Bootstrap和Channel实现

Netty入门实例-编写服务器端程序

channelRead()处理程序方法实现如下

Netty开发环境配置

最新版本的Netty 4.x和JDK 1.6及更高版本

电商平台数据库设计

电商平台数据库表设计:商品分类表、商品信息表、品牌表、商品属性表、商品属性扩展表、规格表、规格扩展表

HttpClient 上传文件

我们使用MultipartEntityBuilder创建一个HttpEntity。 当创建构建器时,添加一个二进制体 - 包含将要上传的文件以及一个文本正文。 接下来,使用RequestBuilder创建一个HTTP请求,并分配先前创建的HttpEntity。

MongoDB常用命令

查看当前使用的数据库    > db    test  切换数据库   > use foobar    switched to db foobar  插入文档    > post={"title":"领悟书生","content":"这是一个分享教程的网站","date":new

快速了解MongoDB【基本概念与体系结构】

什么是MongoDB MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

windows系统安装MongoDB

安装 下载MongoDB的安装包:mongodb-win32-x86_64-2008plus-ssl-3.2.10-signed.msi,按照提示步骤安装即可。 安装完成后,软件会安装在C:\Program Files\MongoDB 目录中 我们要启动的服务程序就是C:\Program Files\MongoDB\Server\3.2\bin目录下的mongod.exe,为了方便我们每次启动,我

Spring boot整合MyBatis-Plus 之二:增删改查

基于上一篇springboot整合MyBatis-Plus之后,实现简单的增删改查 创建实体类 添加表注解TableName和主键注解TableId import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baom

分布式ID生成器【snowflake雪花算法】

基于snowflake雪花算法分布式ID生成器 snowflake雪花算法分布式ID生成器几大特点: 41bit的时间戳可以支持该算法使用到2082年 10bit的工作机器id可以支持1024台机器 序列号支持1毫秒产生4096个自增序列id 整体上按照时间自增排序 整个分布式系统内不会产生ID碰撞 每秒能够产生26万ID左右 Twitter的 Snowflake分布式ID生成器的JAVA实现方案