WeixinRequestHandler.java

package com.foxinmy.weixin4j.socket;

import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;

import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.SingleResponse;
import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.AesToken;
import com.foxinmy.weixin4j.util.HttpUtil;
import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.util.ServerToolkits;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * 微信请求处理类
 *
 * @className WeixinRequestHandler
 * @author jinyu(foxinmy@gmail.com)
 * @date 2014年11月16日
 * @since JDK 1.6
 * @see com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher
 */
public class WeixinRequestHandler extends SimpleChannelInboundHandler<WeixinRequest> {
    private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());

    private final WeixinMessageDispatcher messageDispatcher;

    public WeixinRequestHandler(WeixinMessageDispatcher messageDispatcher) {
        this.messageDispatcher = messageDispatcher;
    }

    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
        logger.error(cause);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request) {
        AesToken aesToken = request.getAesToken();
        // 消息字段不完整返回400
        if (aesToken == null || (ServerToolkits.isBlank(request.getSignature())
                && ServerToolkits.isBlank(request.getMsgSignature()))) {
            ctx.writeAndFlush(resolveResponse(BAD_REQUEST, request)).addListener(ChannelFutureListener.CLOSE);
            return;
        }
        /**
         * 公众平台:无论Get,Post都带signature参数,当开启aes模式时带msg_signature参数
         * 企业号:无论Get,Post都带msg_signature参数
         * 一般来说:signature验证url上的参数签名,msg_signature验证消息体签名
         **/
        if (request.getMethod() == HttpMethod.GET) {
            // URL参数签名验证
            if (!ServerToolkits.isBlank(request.getSignature())
                    && MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce())
                            .equals(request.getSignature())) {
                ctx.writeAndFlush(new SingleResponse(request.getEchoStr()));
                return;
            }
            // XML消息签名验证
            if (!ServerToolkits.isBlank(request.getMsgSignature()) && MessageUtil
                    .signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(), request.getEchoStr())
                    .equals(request.getMsgSignature())) {
                ctx.writeAndFlush(
                        new SingleResponse(MessageUtil.aesDecrypt(null, aesToken.getAesKey(), request.getEchoStr())));
                return;
            }
            ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
            return;
        } else if (request.getMethod() == HttpMethod.POST) {
            // URL参数签名验证
            if (!ServerToolkits.isBlank(request.getSignature())
                    && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce())
                            .equals(request.getSignature())) {
                ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
                return;
            }
            // XML消息签名验证
            if (request.getEncryptType() == EncryptType.AES
                    && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(),
                            request.getEncryptContent()).equals(request.getMsgSignature())) {
                ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
                return;
            }
        } else {
            // 访问其它URL
            ctx.writeAndFlush(resolveResponse(METHOD_NOT_ALLOWED, request)).addListener(ChannelFutureListener.CLOSE);
            return;
        }
        messageDispatcher.doDispatch(ctx, request);
    }

    private FullHttpResponse resolveResponse(HttpResponseStatus responseStatus, WeixinRequest request) {
        FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), responseStatus);
        HttpUtil.resolveHeaders(response);
        return response;
    }
}