2019独角兽企业重金招聘Python工程师标准>>>
最近因公司业务需求,需要接入支付宝生活号服务窗的事件订阅功能,但接入过程中也是一波三折各种坑。总体感受,接入支付宝不如接入微信来的丝滑。下面把接入过程中所遇到的各种问题做个总结。
1.激活开发者模式,收不到支付宝请求
2.验签失败问题
1. 激活开发者模式,收不到支付宝请求
首先,根据支付宝官方文档介绍,接入流程大致是这样子。
但当我们把相关代码环境(服务器外网可访问)准备好后,写入应用网关并保存,支付宝提示“应用网关响应异常”。
咨询官方技术支持,给的解决方案林林总总无一生效(https域名改为http / 部署官方demo / 修改网关路径为demo路径等等,解决问题思路也是清奇的狠)。最后无奈,直接投产验证,好在生产环境是可以调通的。
**解决方案:**未知。(个人猜测可能是我司测试环境证书问题,因运维同学没有配合,所以只是猜测)。
2.验签失败问题
先说原因,在我司接入过程中出现验签失败问题主要是编码字符集不一致而导致接收到的支付宝请求报文出现中文乱码问题。进而导致本地签名结果与支付宝服务器传来的sign参数不一致。
问题说明,因公司项目应用服务器使用UTF-8编码,而支付宝事件回调请求采用GBK编码。因此,在接收到请求报文中,如果存在中文则会出现验签失败的问题。(在这个问题解决过程中,支付宝技术支持给的方案也是神来之笔,建议我们修改项目的字符编码格式为GBK,dnlm~)
解决方案:
为不影响公司项目之前字符编码逻辑,决定采用过滤器的方式把请求特定路径的Http接口请求Request与Response编码强制指定成支付宝所要求的GBK编码格式。
示例如下:
- 定义支付宝回调过滤器
@NoArgsConstructor
@AllArgsConstructor
public class AliPayHookOrderedEncodingFilter extends OncePerRequestFilter implements Ordered {
@Getter
@MetaData(value = "字符集编码")
private String encoding = AliPayConstPool.CHARSET;
@Getter
private boolean forceRequestEncoding = true;
@Getter
private boolean forceResponseEncoding = true;
/**
*
* 过滤器排序号
*
* 排序号越大,优先级越低,此处尽量设置较大排序号,
* 保证在{@link CharacterEncodingFilter}后执行
*
* @return the order value
*
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*
*/
@Override
public int getOrder() {
//-2147483648
return -2147483647;
}
/**
*
* 同一个请求线程中,只执行一次
*
* @param request req
* @param response resp
* @param filterChain 过滤器链
*
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encode = getEncoding();
if (StringUtils.isNotEmpty(encode)) {
if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encode);
}
if (isForceResponseEncoding()) {
response.setCharacterEncoding(encode);
}
}
filterChain.doFilter(request, response);
}
}
- 注入过滤器,并配置指定拦截目录
@Configuration
@ConditionalOnWebApplication
public class AliPayHookEncodingAutoConfiguration {
@Bean
public AliPayHookOrderedEncodingFilter aliPayHookOrderedEncodingFilter() {
return new AliPayHookOrderedEncodingFilter();
}
@Bean
public FilterRegistrationBean aliPayHookOrderedEncodingFilterRegistor() {
FilterRegistrationBean filterRegistor = new FilterRegistrationBean();
filterRegistor.setFilter(aliPayHookOrderedEncodingFilter());
filterRegistor.setName("aliPayHookOrderdEncodingFilter");
//~~ 处理目录/open/ali-pay/hook/*下的请求与响应编码 ~~
List patterns = Lists.newArrayList("/open/ali-pay/hook/*");
filterRegistor.setUrlPatterns(patterns);
filterRegistor.setAsyncSupported(true);
filterRegistor.setOrder(aliPayHookOrderedEncodingFilter().getOrder());
return filterRegistor;
}
}
处理之后,就解决了因字符集问题而导致的验签失败。
除以上问题外,基本还算正常。(吐槽一下,阿里的报文格式,有点反人类)