yumeng 3 روز پیش
والد
کامیت
5968464fdb

+ 107 - 6
src/main/java/com/adx/tencent/httpapi/TrackingController.java

@@ -18,6 +18,8 @@ import org.springframework.web.server.ResponseStatusException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 import java.util.*;
 import java.util.concurrent.Semaphore;
@@ -361,7 +363,7 @@ public class TrackingController {
 
     private String mediaTraceId(Map<String, String> params) {
         for (String key : List.of("click_id", "impression_id", "trace_id", "callback", "request_id",
-                "oaid", "imei", "idfa", "caid")) {
+                "oaid", "imei", "idfa", "caid", "muid")) {
             String v = params.get(key);
             if (v != null && !v.isBlank()) return v;
         }
@@ -465,15 +467,114 @@ public class TrackingController {
         putUid(uid, "idfaMd5", firstParam(p, "idfa_md5", "idfaMd5"));
         putUid(uid, "oaid", p.get("oaid"));
         putUid(uid, "oaidMd5", firstParam(p, "oaid_md5", "oaidMd5", "hash_oaid"));
-        // 百度ADX要求muid不能为空,Android用IMEI MD5,无则用oaidMd5或dpidMd5兜底
-        String muid = firstParam(p, "muid", "imei_md5", "imeiMd5", "did_md5", "didMd5");
-        if (muid == null || muid.isBlank()) {
-            muid = firstParam(p, "hash_oaid", "oaid_md5", "oaidMd5", "hash_android_id", "dpid_md5", "dpidMd5");
+        List<Map<String, Object>> caid = baiduCaidFromParams(p);
+        if (!caid.isEmpty()) {
+            uid.put("caid", caid);
         }
-        putUid(uid, "muid", muid);
         return uid;
     }
 
+    private List<Map<String, Object>> baiduCaidFromParams(Map<String, String> params) {
+        String rawCaid = firstParam(params, "caid");
+        if (rawCaid == null || rawCaid.isBlank()) {
+            return Collections.emptyList();
+        }
+        List<Map<String, Object>> parsed = parseTencentCaid(rawCaid);
+        if (!parsed.isEmpty()) {
+            return parsed;
+        }
+
+        Map<String, Object> caidItem = new LinkedHashMap<>();
+        caidItem.put("id", rawCaid);
+        return List.of(caidItem);
+    }
+
+    private List<Map<String, Object>> parseTencentCaid(String rawCaid) {
+        String decoded = decodeCaid(rawCaid);
+        if (decoded == null || decoded.isBlank()) {
+            return Collections.emptyList();
+        }
+        try {
+            Object value = objectMapper.readValue(decoded, Object.class);
+            if (value instanceof List<?> list) {
+                List<Map<String, Object>> result = new ArrayList<>();
+                for (Object item : list) {
+                    Map<String, Object> caid = toBaiduCaidItem(item);
+                    if (!caid.isEmpty()) result.add(caid);
+                }
+                return result;
+            }
+            if (value instanceof Map<?, ?> map) {
+                Map<String, Object> caid = toBaiduCaidItem(map);
+                if (!caid.isEmpty()) {
+                    return List.of(caid);
+                }
+            }
+        } catch (Exception e) {
+            log.debug("[腾讯][百度请求] caid parse failed raw={} decoded={}", rawCaid, decoded);
+        }
+        return Collections.emptyList();
+    }
+
+    private String decodeCaid(String rawCaid) {
+        try {
+            return URLDecoder.decode(rawCaid, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            return rawCaid;
+        }
+    }
+
+    private Map<String, Object> toBaiduCaidItem(Object source) {
+        if (!(source instanceof Map<?, ?> map)) {
+            return Collections.emptyMap();
+        }
+        String id = firstNonBlankValue(map, "qaid", "id", "caid");
+        if (id == null) {
+            return Collections.emptyMap();
+        }
+        Map<String, Object> caidItem = new LinkedHashMap<>();
+        caidItem.put("id", id);
+
+        String version = firstNonBlankValue(map, "version");
+        if (version != null) {
+            caidItem.put("version", version);
+        }
+        Long generateTime = firstLongValue(map, "generateTime");
+        if (generateTime != null) {
+            caidItem.put("generateTime", generateTime);
+        }
+        Long vendor = firstLongValue(map, "vendor");
+        if (vendor != null) {
+            caidItem.put("vendor", vendor);
+        }
+        return caidItem;
+    }
+
+    private String firstNonBlankValue(Map<?, ?> map, String... keys) {
+        for (String key : keys) {
+            Object value = map.get(key);
+            if (value == null) continue;
+            String text = String.valueOf(value).trim();
+            if (!text.isEmpty()) return text;
+        }
+        return null;
+    }
+
+    private Long firstLongValue(Map<?, ?> map, String... keys) {
+        for (String key : keys) {
+            Object value = map.get(key);
+            if (value == null) continue;
+            if (value instanceof Number n) {
+                return n.longValue();
+            }
+            try {
+                return Long.parseLong(String.valueOf(value).trim());
+            } catch (NumberFormatException ignored) {
+            }
+        }
+        return null;
+    }
+
     private void putUid(Map<String, Object> uid, String key, String value) {
         if (value != null && !value.isBlank()) uid.put(key, value);
     }

+ 2 - 0
src/main/java/com/adx/tencent/storage/model/BidRecord.java

@@ -137,9 +137,11 @@ public class BidRecord {
         List<String> deviceKeys = List.of(
                 "imei", "imei_md5",
                 "idfa", "idfa_md5",
+                "muid", "caid",
                 "oaid", "oaid_md5",
                 "android_id", "android_id_md5",
                 "hash_oaid", "hash_android_id",
+                "ip", "ua", "user_agent",
                 "callback", "click_id", "account_id",
                 NEW_LINK_FLAG_KEY, TRACKING_VERSION_KEY, DEDUCTION_RATE_KEY
         );