对接腾讯广告(广点通) 上传用户行为

目录

一.前言

二.账号

三.数据源

四.涉及接口以及大致流程

1.广告主账号授权. (授权给开发者账号)

2.获取access_token

3.上传用户行为

五.代码


一.前言

不知道有没有跟我一样的同学, 每次新对接的一个腾讯产品的时候看着它的api就感觉头疼哈哈
官方文档链接 :https://developers.e.qq.com/docs/start

二.账号

关于client_id和client_secret, 这个是要在开发者账号中新建应用, 进而获取到client_id和client_secret, 在我向运营小姐姐要这个参数的时候, 她以为这个是广告主账号里面应用的appid就给我了, 所以在进行访问授权链接的时候就会提示"加载应用信息失败,您授权的应用id不存在,请联系您授权应用的开发者确认该授权链接是否有误" . .

三.数据源

数据源广告主账号可以在页面上直接创建暂且不谈

四.涉及接口以及大致流程

1.广告主账号授权. (授权给开发者账号)

http://developers.e.qq.com/oauth/authorize?client_id=(开发者账号创建出的应用的id)&redirect_uri=自己的服务器接口地址md5(用来接收回调,可获得authorization_code)

仅仅需要把链接在浏览器上访问一下, 然后用广告主账号登录后同意授权给开发者账号的应用对应的权限. 介时, 腾讯会回调配置好的链接, 并带参数回去, 具体参数参考api, 其中最主要的就是带有authorization_code, 这是获取access_token与refresh_token的必要参数


2.获取access_token

获取access_token总共有两种方式, 一个是通过authorization_code, 另一个是通过refresh_token. 这两种都是要被使用的. 下面将介绍其中的区别与使用

在第一次授权回调时, 就会获得authorization_code(有效时长很短), 这时候就要用到第一种方式(通过authorization_code)来获取access_token. 而且refresh_token也是在第一种获取access_token的方式中一起返回的参数. 这个时候记录下refresh_token, 以后在access_token过期时(24小时过期), 就可以通过refresh_token(30天过期)来获取了
第一种和第二种获取access_token方式的接口地址是一样的: https://api.e.qq.com/oauth/token, 但是不同类型的话grant_type参数的传递值要有所不同

3.上传用户行为

在上传用户行为时, 调用的接口:

https://api.e.qq.com/v1.1/user_actions/add?access_token=之前获取的access_token&timestamp=当前时间戳(单位秒)&nonce=随机32为字符串

请求参数(Post Content-Type: application/json):

{
    "account_id": "广告主账号",
    "user_action_set_id": "数据源id(广告主那边可以获得)",
    "actions": [
        {
            "action_time": 当前时间戳(秒),
            "user_id": {
                "hash_imei": "设备号"
            },
            "action_type": "枚举类型"
        }
    ]
}

五.代码

    //回调
    @ResponseBody
    @RequestMapping(value = "/callback/Tencent/promotion")
    public BizResult setAccessToken(HttpServletRequest request) {
        String domain = "http://api.xxxx.cn/callback/Tencent/promotion";
        String url = domain + "?" + request.getQueryString();
        ttLog.info("获取 authorization_code 的url: " + url);

        //缓存token
        String authorization_code = request.getParameter(AUTHORIZATION_CODE);

        //刷新access_token 与 refresh_token
        String access_token = callBackTencentService.refreshToken(CallBackTencentService.GRANT_TYPE_VALUE_AUTHORIZATION, authorization_code);

        redisUtils.setString(RedisConstant.ACCESS_TOKEN, refresh_token, RedisConstant.REFRESH_TOKEN_exp)

        if (StringUtils.isEmpty(access_token)) {
            redisUtils.delString(RedisConstant.ACCESS_TOKEN);
            return BizResult.create("token更新失败");
        } else {
            return BizResult.create("token更新成功");
        }
    }

/**
 * 腾讯广点通
 */
@Slf4j
@Service
public class CallBackTencentService {
    private static Logger ttLog = LoggerFactory.getLogger("ttPromotionCallback");
    private static Logger ttexLog = LoggerFactory.getLogger("ttPromotionCallbackException");

    //刷新类型
    public static final String GRANT_TYPE_VALUE_AUTHORIZATION = "authorization_code";//授权码方式获取 token, 这个时候必填redirect_uri
    public static final String GRANT_TYPE_VALUE_REFRESH = "refresh_token";//刷新 token

    // 请求token需要的几个字段
    private static final String CLIENT_ID = "client_id";
    private static final String CLIENT_SECRET = "client_secret";
    private static final String CLIENT_ID_VALUE = "1321321321";
    private static final String CLIENT_SECRET_VALUE = "fdgsgsdgdsg";
    private static final String GRANT_TYPE = "grant_type";
    private static final String REDIRECT_URI = "redirect_uri";
    private static final String REDIRECT_URI_VALUE = "http://api.qtread.cn/callback/Tencent/promotion";

    // 直接获取
    private static String getAccessTokenUrl;
    // 通过 refresh_token u获取
    private static String getAccessTokenFromRefreshTokenUrl;

    static {
        StringBuilder sb = new StringBuilder("https://api.e.qq.com/oauth/token");
        sb.append("?");
        sb.append(CLIENT_ID);
        sb.append("=");
        sb.append(CLIENT_ID_VALUE);
        sb.append("&");
        sb.append(CLIENT_SECRET);
        sb.append("=");
        sb.append(CLIENT_SECRET_VALUE);
        sb.append("&");
        sb.append(GRANT_TYPE);
        sb.append("=");
        sb.append("grant_type_value");
        getAccessTokenFromRefreshTokenUrl = sb.toString();
        sb.append("&");
        sb.append(REDIRECT_URI);
        sb.append("=");
        sb.append(REDIRECT_URI_VALUE);
        getAccessTokenUrl = sb.toString();
    }

    @Autowired
    private RedisGetCacheByDb redisGetCacheByDb;
    @Autowired
    private RedisUtils redisUtils;


    /**
     * 刷新access_token 与 refresh_token
     */
    public String refreshToken(String grantTypeValue, String authorization_code) {
        if (GRANT_TYPE_VALUE_AUTHORIZATION.equals(grantTypeValue) && StringUtils.isEmpty(authorization_code)) {
            ttexLog.error("authorization_code更新token失败!authorization_code为空");
            return "";
        }
        String requestUrl = "";
        String refresh_token = "";
        String access_token = "";

        if (GRANT_TYPE_VALUE_AUTHORIZATION.equals(grantTypeValue)) {
            requestUrl = getAccessTokenUrl.replace("grant_type_value", GRANT_TYPE_VALUE_AUTHORIZATION);
            requestUrl += "&" + GRANT_TYPE_VALUE_AUTHORIZATION + "=" + authorization_code;
        } else {
            refresh_token = redisUtils.getString(RedisConstant.REFRESH_TOKEN);
            if (StringUtils.isEmpty(refresh_token)) {//万一refresh_token过期了, 需要运营重新请求调用授权获取
                    ttexLog.error("refresh_token更新token失败! refresh_token已经失效!");
                    try {
                        SmsSendUtil.send(refresh_token失效了, 请重新授权, "13600000000");//发送短信告诉运营需要重新认证
                    } catch (Exception e) {
                        ttexLog.error("发送短信失败");
                    }
                   
                return "";
            }
            requestUrl = getAccessTokenFromRefreshTokenUrl.replace("grant_type_value", GRANT_TYPE_VALUE_REFRESH);
            requestUrl += "&" + GRANT_TYPE_VALUE_REFRESH + "=" + refresh_token;
        }

        String returnMsg = HttpUtils.httpGet(requestUrl, "");
        ttLog.info(returnMsg);
        Map map = JSONObject.parseObject(returnMsg, Map.class);
        if (map.get("code") == null || !"0".equals(map.get("code").toString())) {
            ttexLog.error(grantTypeValue + "更新token失败!" + GRANT_TYPE_VALUE_AUTHORIZATION + "=" + authorization_code + "," + GRANT_TYPE_VALUE_REFRESH + "=" + refresh_token + "错误码=" + map.get("code").toString() + "错误原因=" + map.get("message").toString());
            return "";
        }

        Map data = (Map) map.get("data");
        access_token = data.get("access_token").toString();
        refresh_token = data.get("refresh_token").toString();

        redisUtils.setString(RedisConstant.REFRESH_TOKEN, refresh_token, RedisConstant.REFRESH_TOKEN_exp);
        ttLog.info("更新token成功!");
        return access_token;
    }

    /**
     * 普通获取access_token
     */
    public String getAccessToken() throws Exception {
        String access_token = redisGetCacheByDb.getCache(RedisConstant.ACCESS_TOKEN, RedisConstant.ACCESS_TOKEN_exp, new TypeReference<String>() {
        }, () -> {
            return this.refreshToken(GRANT_TYPE_VALUE_REFRESH, "");
        });
        if (StringUtils.isEmpty(access_token)) {
            //请求失败 空串不存
            redisUtils.delString(RedisConstant.ACCESS_TOKEN);
        }
        return access_token;
    }


    //用户行为上传需要的几个字段
    private static final String ACCOUNT_ID = "1234567";//推广帐号 id,有操作权限的帐号 id,包括代理商和广告主帐号 id
    private static final String USER_ACTION_SET_ID = "98767777";//用户行为源 id,通过 [user_action_sets 接口] 创建用户行为源时分配的唯一 id
    public static final String ACTION_TYPE = "REGISTER";//注册类型

    /**
     * 上传用户行为
     */
    public boolean userActionAdd(String deviceId, String oaid, String actionType, String channelId) throws Exception {
        ttLog.info(channelId + "开始进行回调, imei:" + deviceId + ", oaid:" + oaid);

        Long timeStamp = System.currentTimeMillis() / 1000;
        String accessToken = getAccessToken();
        String uuid = UUID.randomUUID().toString().trim().replace("-", "");
        String imei = StringUtils.isEmpty(deviceId) ? (StringUtils.isEmpty(oaid) ? "" : oaid) : getMd5(deviceId).toLowerCase();

        String baseUrl = String.format("https://api.e.qq.com/v1.1/user_actions/add?access_token=%s&timestamp=%s&nonce=%s", accessToken, timeStamp, uuid);

        Map<Object, Object> userId = new HashMap<>();
        if (!StringUtils.isEmpty(deviceId)) {
            userId.put("hash_imei", imei);
        } else {
            userId.put("oaid", imei);
        }
        ArrayList<Map> actions = new ArrayList<>();
        Map<String, Object> actionsMap = CollectionUtil.createMap("action_time,user_id,action_type", timeStamp, userId, actionType);
        actions.add(actionsMap);
        Map<String, Object> param = CollectionUtil.createMap("account_id,user_action_set_id,actions", ACCOUNT_ID, USER_ACTION_SET_ID, actions);
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");

        String result = HttpUtils.httpPost(baseUrl, JSONObject.toJSONString(param), headers);
        Map map = JSONObject.parseObject(result, Map.class);
        if (!"0".equals(map.get("code").toString())) {
            ttexLog.error("上传用户行为失败:" + "deviceId=" + deviceId + "&oaid=" + oaid + "错误码=" + map.get("code").toString() + "错误原因=" + map.get("message").toString());
            return false;
        }
        return true;
    }

    /**
     * 异步调用行为
     */
    @Async
    public void userActionAddAsync(String deviceId, String oaid, String actionType, String channelId) throws Exception {
        if (!"XXX".equals(channelId)) {//XXX渠道用户进行上传用户行为
            return;
        }
        this.userActionAdd(deviceId, oaid, actionType ,channelId);
    }

 

### 腾讯广告对接API文档及教程 #### 广告对接概述 为了实现精准营销效果评估,腾讯广告提供了Web转化数据API自归因功能。过该接口能够追踪用户行为路径,从广告展示、击直至最终转化,帮助优化广告策略。 #### 接口地址配置 新建广告时需配置用于接收击事件知的URL作为监测链接的一部分。此URL应指向服务器端处理逻辑所在位置,并携带必要的查询字符串参数以便识别特定广告活动实例: ```plaintext https://yourdomain.com/data-nexus/ad-back/?account_id={ACCOUNT_ID}&click_id={CLICK_ID}&click_time={CLICK_TIME}&callback={CALLBACK}&request_id={REQUEST_ID} ``` 其中`{}`包围的部分代表由腾讯平台动态填充的实际值[^1]。 #### 参数说明 - `account_id`: 广告账户ID。 - `click_id`: 唯一标识一次击操作的身份码。 - `click_time`: 记录发生时间戳。 - `callback`: 预留字段供特殊场景下使用。 - `request_id`: 请求唯一编号,可用于后续跟踪验证。 #### 数据校验与存储 接收到上述GET请求后,服务端应当解析这些参数并与前端页面传递的信息相匹配(如traceid)。一旦确认无误,则保存至数据库等待进一步分析处理;同时向客户端返回HTTP状态码200表示成功受理。 #### 测试验证 利用在线预览工具模拟真实环境下的交互过程,确保各个环节顺畅衔接。当腾讯后台反馈归因成功的消息时,意味着整个链路已打完毕。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值