# FAQ 常见问题

# 广告请求中的 pos.id 是什么

提示

{pos.id} 是火眼平台提供的广告位 ID,形如 A64B204EE728

# 广告返回中的{pos.id}是什么

提示

{pos.id} 为火眼平台提供的广告位 ID,即请求时传入的 {pos.id}

# 广告返回中的 pos.ad_spec 如何理解

提示

pos.ad_spec推荐使用的广告渲染规格,当然这并不是强制的。

例如广告返回的是左文右图的规格,媒体主可以自行渲染样式。

# 为什么要特殊处理广告返回中 platform_type 为 2 的情况

提示

pos.platform_type为 2 时表示广点通的下载,广点通的下载有其独立逻辑,需要媒体主单独处理。

此外,广点通的下载广告上报事件时有一个名为 __CLICK_ID__ 的宏需要替换成真实的值。

# 第三方监测如何上报

提示

通常来说,一条第三方监测地址就是一个 url 链接,媒体主的客户端只需要通过 GET 请求触发一下即可。

如果有多条监测链接,全部通过 GET 请求触发即可。

# 什么是宏

提示

广告返回中会有很多监测事件(例如 展示上报事件),这些事件的链接上会包含一个或多个固定的字符串(例如:__WIDTH__、__HEIGHT__),这些固定格式的字符串我们称之为

# 什么是宏替换

提示

将事件监测链接中的 ,替换成真实值得过程我们称之为 宏替换

# 为什么要进行宏替换

提示

宏替换中的 参数是各大平台用来衡量流量真实性的依据,本着能传尽量传的原则,希望媒体主按照真实的值进行替换,这有利于媒体主收入的提升。

需要注意的是

宏替换 必须在 客户端 准确替换才行,否则会影响媒体主的收入。

Deeplink 是通过一个链接直接跳转到已安装的应用中的某个页面的技术

常见的 deeplink 链接如下

tbopen://m.taobao.com/tbopen/index.html?&action=ali.open.nav&module=h5&bootImage=0&source=alimama&appkey=30132400&h5Url=https%3A%2F%2Fsrd.simba.taobao.com%2Ferd%3Fw%3Dunionitemjump%26f%3Dv3Ti%252Fx85Z%252B3GKe1rQbugJglvP7pI2SNqxFcw3hOCItBulAcyoTW0Em%252F3FhENbIQRI1%252FHihEei4H7yDDu%252FUovZndg%252FMpKZjQy47IBebN97vBjzjmYX%252BljVQ5W1PBqHAwmzxHTWWW0yCGLn8%252FhsK7P7kNX47DL0ffvGjOtwTMHnIEoOwhOZiyCU8haTctSDp8C0Jv%252B6Ocsv8Z1bbhz%252BwTGqU4da6Bx1ybbFMmam6ccFFx4%252BGzURd3v%252FUOyxcbHNwNzElD3OnAK4XAIEOnQ8drnkhzXMcFnfwfl77Oyt%252FWYcPXAs7sAnHoJCHhnLn7ptYTR%26k%3D5cd3316a8543165a%26pvid%3D4aa48af9fe3a4eea83b72e4a844795b6%26p%3Dmm_1029440115_1726450249_110431400352%26es%3D%26l%3D321%26bc_fl_src%3Dtunion_vipmedia_dandelion&bc_fl_src=tunion_vipmedia_dandelion
  • deeplink 只能唤起本地已安装的应用,若用户未安装 deeplink 对应的应用,则会唤起失败。

当返回的是 deeplink 类的广告时,媒体主有一套标准的处理流程

  1. 首先尝试通过 deeplink 唤起应用

  2. 若唤起失败(应用未安装),直接通过浏览器打开 click_link 即可。

# 常见的广告尺寸有哪些

提示

  1. 开屏

    • 640*960
    • 720*1280
  2. 信息流

    • 480*320
    • 1280*720
  3. 激励视频

    • 720*1280
    • 1280*720
  4. 横幅

    • 640*100

# 媒体主的非标尺寸广告位如何处理通用尺寸的广告

提示

媒体主客户端自适应即可,通用尺寸已能适配市面上的大部分都机型。

# 宏 DOWN_X 和 OFFSET_X 有什么区别

提示

这两者间没有什么区别。只是不同的上游对同一种宏参数定义的名称不一样。

# 客户端无法支持所有的宏怎么办

提示

能传尽量传,实在无法获取的可以不传。

# 火眼广告返回中有文档未提及的字段怎么办

提示

媒体主以文档中提及的字段为准,不在文档中的可以不用理会。

# 火眼服务器单次广告请求的响应时长是多少

提示

正常情况下耗时平均在 200ms 左右,如果上游平台的响应变慢,则火眼平台的返回时间也会相应的增加。

# 火眼平台没有广告返回怎么办

提示

建议媒体主支持流量回流的功能,即当火眼平台无广告返回时,将流量分发给其他平台。

# WIN_PRICE 宏如何加解密

提示

秘钥请联系运营获取

加密校验
price = 100
token = UG1NudebnMTRZaLV
加密后价格 = 9be6bb522d5f2519fddc92384efe4a43
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.exception.ExceptionUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

@Slf4j
public class AesECB {
    private static final String KEY_ALGORITHM = "AES";
    private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
    private static final String ENCODING = "utf-8";

    private Cipher decCipher;
    private Cipher encCipher;

    /**
     * aes构造函数
     */
    public AesECB(String key) {
        SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);

        try {
            decCipher = Cipher.getInstance(ALGORITHM);
            encCipher = Cipher.getInstance(ALGORITHM);

            encCipher.init(Cipher.ENCRYPT_MODE, keyspec);
            decCipher.init(Cipher.DECRYPT_MODE, keyspec);
        } catch (Exception e) {
            log.error(ExceptionUtils.getStackTrace(e));
        }
    }


    public String encrypt(String text) {
        byte[] encrypted;

        try {
            encrypted = encCipher.doFinal(text.getBytes(ENCODING));
            return Hex.encodeHexString(encrypted);
        } catch (Exception e) {
            log.error(e.toString());
        }
        return null;
    }

    public String decrypt(String text) {
        byte[] decrypted;
        try {
            decrypted = decCipher.doFinal(Hex.decodeHex(text.toCharArray()));
            return new String(decrypted, ENCODING).trim();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }
}

<?php

function encrypt($data = '', $key = NULL) {
    if($key != NULL && $data != ""){
        $method = "AES-128-ECB";
        $encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA);
        $result = bin2hex($encrypted);
        return $result;
    }else{
        return "String to encrypt, Key is required.";
    }
}

function decrypt($data="", $key = NULL) {
    if($key != NULL && $data != ""){
        $method = "AES-128-ECB";
        $decrypted = openssl_decrypt(hex2bin($data), $method, $key, OPENSSL_RAW_DATA);
        return $decrypted;
    }else{
        return "Encrypted String to decrypt, Key is required.";
    }
}


$data = '100';
$key = 'UG1NudebnMTRZaLV';


$encrypted = encrypt($data,$key);
$decrypted = decrypt('9be6bb522d5f2519fddc92384efe4a43', $key);

print("$data 加密后 ${encrypted}\n");
print("$encrypted 解密后 ${decrypted}\n");

package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/hex"
	"fmt"
)

type ecb struct {
	b         cipher.Block
	blockSize int
}

func newECB(b cipher.Block) *ecb {
	return &ecb{
		b:         b,
		blockSize: b.BlockSize(),
	}
}

type ecbEncrypter ecb

func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
	return (*ecbEncrypter)(newECB(b))
}
func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
	if len(src)%x.blockSize != 0 {
		panic("crypto/cipher: input not full blocks")
	}
	if len(dst) < len(src) {
		panic("crypto/cipher: output smaller than input")
	}
	for len(src) > 0 {
		x.b.Encrypt(dst, src[:x.blockSize])
		src = src[x.blockSize:]
		dst = dst[x.blockSize:]
	}
}

type ecbDecrypter ecb

func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
	return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
	if len(src)%x.blockSize != 0 {
		panic("crypto/cipher: input not full blocks")
	}
	if len(dst) < len(src) {
		panic("crypto/cipher: output smaller than input")
	}
	for len(src) > 0 {
		x.b.Decrypt(dst, src[:x.blockSize])
		src = src[x.blockSize:]
		dst = dst[x.blockSize:]
	}
}

func AESEncrypt(src, key []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil
	}
	ecb := NewECBEncrypter(block)
	content := []byte(src)
	content = PKCS5Padding(content, block.BlockSize())
	des := make([]byte, len(content))
	ecb.CryptBlocks(des, content)
	return des
}

func AesDecrypt(crypted, key []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil
	}
	blockMode := NewECBDecrypter(block)
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)
	origData = PKCS5UnPadding(origData)
	return origData
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func PKCS5UnPadding(origData []byte) []byte {
	length := len(origData)
	// 去掉最后一个字节 unpadding 次
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func main() {
	var v1 = "100"
	var key = "UG1NudebnMTRZaLV"
	var v2 = "9be6bb522d5f2519fddc92384efe4a43"

	enc := AESEncrypt([]byte(v1), []byte(key))
	msg := fmt.Sprintf("原始字符串: %v 加密后的结果: %v", v1, hex.EncodeToString(enc))
	fmt.Println(msg)

	dec, _ := hex.DecodeString(v2)
	data := AesDecrypt(dec, []byte(key))
	msg = fmt.Sprintf("解密字符串: %v 加密后的结果: %v", v2, string(data))
	fmt.Println(msg)
}