Java OkHttp 一个cookie引发的故障

项目在使用OkHttp调用微信广告API时遇到数据上报异常,错误响应与接口文档不符,导致内部系统误判。经过日志分析发现请求因携带不安全cookie被拦截。解决方案是更改OkHttp的CookieJar策略为NO_COOKIES,并调整返回结果对象以避免误判。问题源是自定义CookieJar策略,每次请求会带上之前接口响应的cookie,导致风控拦截。

项目场景:

公司业务在腾讯广告平台推广投放,需要对接广告平台,通过API接口上报用户行为转化数据。


问题描述

项目为Java工程,采用OkHttp开源库实现后台API接口上报,原先一直运行无误,突然某天凌晨运营反馈上报数据异常,公司内部平台显示订单全部上报成功,而腾讯广告后台接受数量一直为0。上报接口地址为:https://api.weixin.qq.com/marketing/user_actions/add


原因分析:

通过增加日志排查接口上报的实际返回结果如下,发现该响应不符合接口文档中的响应字段定义,而且根据错误描述,该接口根本不涉及到timestamp, nonce参数,理论上不应该返回此种错误响应。

{
	"code": 12000,
	"message": "Your request is missing a required parameter which is one of access_token, timestamp and nonce.",
	"message_cn": "您的请求缺少必须参数:access_token,timestamp,nonce"
}

正常情况下上报成功的响应结果应该如下。

{
	"errcode": 0,
	"errmsg": ""
}

项目中采用Gson反序列化返回结果,接受对象定义如下,对象中对errcode有默认值0的定义,因此对于之前的错误响应会将其视作正确返回,造成公司内部平台全部标记为正常上报,而腾讯广告平台侧实际并没有成功接受。

public class WxAdResult implements Serializable {
    private int errcode = 0;
    private String errmsg;
    //省略...
}

之所以对errcode默认赋值为0,是因为预期该接口必定会返回errcode,成功时值为0,失败时为对应的错误码,而此次问题中并没有返回errcode,却返回了code参数,参数名称竟然都不一样,没有对应的说明文档可供查询,让人困扰。

随后联系腾讯的技术人员,询问该接口为何会返回这种不符合预期的错误响应,对方答复是我们的API接口调用请求中携带了不安全的cookie,导致在对方网关层就将该请求拦截过滤,类似请求被风控拦截,网关返回的错误响应便是如此结构。(吐槽:像这种传递了非法cookie的请求被拦截为何会返回一个参数缺失的响应,而且和业务接口API描述文档中的字段名称定义不一致,令人费解)

找到了问题所在,再来看为何我们的API请求中会带上此种cookie,cookie名称为__jsluid_h,项目使用OkHttp库进行http请求调用,检查了关于cookie的配置,发现初始化OkHttpClient时使用了一个自定义的CookieJar,代码如下,而该CookieJar会将项目中该OkHttpClient调用的所有请求的响应返回的cookie(如果有)带入到下一次请求中,也就是说假如其它某个接口响应返回了例如__jsluid_h的cookie,则下一次请求中便会带上该cookie进行访问,直到再来一次请求的响应返回了非空的cookie,便会将此前的cookie覆盖,若后续请求的响应一直不含有cookie,则请求一直会带上__jsluid_h的cookie,导致所有后续请求都被风控拦截。由于OkHttp库的工具类封装是以前同事做的,所以也不知道为何要采用这样的cookie策略,属于前人留下的坑。

/**
* 部分配置,更改前
*/
OkHttpClient.Builder builder = new OkHttpClient.Builder()
			.cookieJar(new DefaultCookieJar());
/**
* 自定义cookie策略
*/
class DefaultCookieJar implements CookieJar{
	List<Cookie> cookies;
	@Override
	public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
		this.cookies = cookies;
	}
	@Override
	public List<Cookie> loadForRequest(HttpUrl url) {
		if (cookies != null)
            return cookies;
        return new ArrayList<Cookie>();
	}
}

解决方案:

更改CookieJar策略,改为默认的NO_COOKIES,使每一次请求都不携带任何cookie信息,代码如下。

/**
* 部分配置,更改后
*/
OkHttpClient.Builder builder = new OkHttpClient.Builder()
			.cookieJar(CookieJar.NO_COOKIES);

同时对原有的返回结果封装对象进行修改,避免此种特殊情况下的结果正确性误判。

public class WxAdResult implements Serializable {
    //防止反序列化后默认值被当做成功处理
    private int code = -99999;
    private String errmsg;
    //省略...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值