将 API 密钥存储在服务器环境变量(.env)中,渲染页面时注入到 iframe src。密钥不会出现在源代码或 Git 中,游戏直接从服务器加载,无资源问题。渲染后的 HTML 中密钥可见,但这是行业标准嵌入方式。
Embed URL
https://bet14mini.com/embed/{slug}/?key={API_KEY}
.env / server config
BET14_API_KEY=YOUR_API_KEY
game.php
<?php
$apiKey = getenv('BET14_API_KEY');
$slug = 'dragontiger'; // or dynamic
?>
<iframe
src="https://bet14mini.com/embed/<?= $slug ?>/?key=<?= htmlspecialchars($apiKey) ?>" allowfullscreen
></iframe>
.env + Express (EJS/Pug template)
# .env
BET14_API_KEY=YOUR_API_KEY
// routes/game.js
router.get('/game/:slug', (req, res) => {
const allowed = ['dragontiger', 'baccarat', 'bigsixball'];
const slug = allowed.includes(req.params.slug) ? req.params.slug : 'dragontiger';
res.render('game', {
embedUrl: `https://bet14mini.com/embed/${slug}/?key=${process.env.BET14_API_KEY}`
});
});
// views/game.ejs
<iframe src="<%- embedUrl %>"
style="width:100%;aspect-ratio:830/553;border:none"
allowfullscreen sandbox="allow-scripts allow-same-origin allow-popups"></iframe>
.env.local + Next.js Server Component
# .env.local
BET14_API_KEY=YOUR_API_KEY
// app/game/[slug]/page.jsx (Server Component)
const ALLOWED = ['dragontiger', 'baccarat', 'bigsixball'];
export default function GamePage({ params }) {
const slug = ALLOWED.includes(params.slug) ? params.slug : 'dragontiger';
const apiKey = process.env.BET14_API_KEY;
const src = `https://bet14mini.com/embed/${slug}/?key=${apiKey}`;
return (
<iframe src={src}
style={{ width: '100%', aspectRatio: '830/553', border: 'none' }}
allowFullScreen
sandbox="allow-scripts allow-same-origin allow-popups"
/>
);
}
.env + Nuxt 3 (SSR)
# .env
BET14_API_KEY=YOUR_API_KEY
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
bet14ApiKey: process.env.BET14_API_KEY, // server-only
}
});
// pages/game/[slug].vue
<template>
<iframe :src="embedUrl"
style="width:100%;aspect-ratio:830/553;border:none"
allowfullscreen sandbox="allow-scripts allow-same-origin allow-popups" />
</template>
<script setup>
const route = useRoute();
const config = useRuntimeConfig();
const slug = ['dragontiger','baccarat','bigsixball'].includes(route.params.slug)
? route.params.slug : 'dragontiger';
const embedUrl = `https://bet14mini.com/embed/${slug}/?key=${config.bet14ApiKey}`;
</script>
appsettings.json + Razor Page
// appsettings.json (or env var Bet14ApiKey)
{ "Bet14ApiKey": "YOUR_API_KEY" }
// Pages/Game.cshtml.cs
public class GameModel : PageModel
{
public string EmbedUrl { get; private set; } = "";
private readonly IConfiguration _cfg;
public GameModel(IConfiguration cfg) => _cfg = cfg;
public IActionResult OnGet(string slug = "dragontiger")
{
var allowed = new[] { "dragontiger", "baccarat", "bigsixball" };
if (!allowed.Contains(slug)) slug = "dragontiger";
EmbedUrl = $"https://bet14mini.com/embed/{slug}/?key={_cfg["Bet14ApiKey"]}";
return Page();
}
}
// Pages/Game.cshtml
<iframe src="@Model.EmbedUrl"
style="width:100%;aspect-ratio:830/553;border:none"
allowfullscreen sandbox="allow-scripts allow-same-origin allow-popups"></iframe>
💡 推荐比例:宽 830 / 高 553 px — 响应式:width:100%; aspect-ratio:830/553; border:none;
🔒 密钥只存储在 .env 中,不要提交到 Git。(在 .gitignore 中添加 .env)
每个游戏服务器提供可每 300ms 轮询的状态端点。投注网站可接收此数据,在自有 UI 中展示当前轮次、阶段和开牌结果,或用于赔付计算。
端点
https://bet14mini.com/embed/{slug}/api/current ← 当前轮次状态https://bet14mini.com/embed/{slug}/api/results?limit=N ← 最近 N 条结果记录
无需认证头。iframe 加载时已完成密钥验证,之后可自由调用游戏服务器 API。
公共响应字段
| 字段 | 类型 | 说明 |
round | integer | 全局累计轮次号 |
daily_round | integer | 当日轮次号(用于显示) |
date | string | 服务器日期(YYYY-MM-DD) |
phase | string | 当前阶段 — 见下表 |
remainMs | integer | 当前阶段剩余时间(毫秒),仅 betting 阶段有效 |
phase 值及循环
| phase | 含义 | 新增字段 |
betting | 接受投注中(倒计时) | remainMs 有效 |
revealing | 开牌/结果公布中 | 牌/分数字段出现 |
result | 结果确定 — 最终胜负 | result 字段确定 |
waiting | 等待下一轮 | — |
GET /embed/dragontiger/api/current
{
"round": 13463,
"daily_round": 2280,
"date": "2026-05-17",
"phase": "result",
"remainMs": 0,
"dragon": { "suit": "S", "value": "4" },
"tiger": { "suit": "C", "value": "2" },
"result": "dragon"
}
| 字段 | 类型 | 说明 |
dragon.suit | string | 龙牌花色:S(黑桃) D(方块) H(红心) C(梅花) |
dragon.value | string | 龙牌点数:2–10, J, Q, K, A |
tiger.suit / tiger.value | string | 虎牌(结构相同) |
result | string | "dragon" | "tiger" | "tie" |
dragon·tiger 字段从 revealing 阶段开始出现,betting 阶段为 null。
GET /embed/baccarat/api/current
{
"round": 8821,
"daily_round": 1104,
"date": "2026-05-17",
"phase": "result",
"remainMs": 0,
"player_cards": [{"suit":"H","value":"5"}, {"suit":"D","value":"3"}],
"banker_cards": [{"suit":"C","value":"K"}, {"suit":"S","value":"7"}],
"player_total": 8,
"banker_total": 7,
"natural": true,
"result": "player"
}
| 字段 | 类型 | 说明 |
player_cards | array | 闲家牌(2~3张,每张 {suit, value}) |
banker_cards | array | 庄家牌(2~3张) |
player_total | integer | 闲家合计(0~9) |
banker_total | integer | 庄家合计(0~9) |
natural | boolean | 天生(8或9)标志 |
result | string | "player" | "banker" | "tie" |
牌字段从 revealing 阶段开始出现。player_total 为 null 表示尚未公布。
GET /embed/bigsixball/api/current
{
"round": 5201,
"daily_round": 420,
"date": "2026-05-17",
"phase": "result",
"remainMs": 0,
"result_map": {
"manu": 1,
"mancity": 2,
"liverpool": 3,
"chelsea": 4,
"arsenal": 5,
"tottenham": 6
}
}
| 字段 | 类型 | 说明 |
result_map | object | 队伍名 → 名次(1=第一名),在 result 阶段确定 |
team_order | array | 发射顺序索引数组(动画用,通常不需要) |
Teams: manu / mancity / liverpool / chelsea / arsenal / tottenham
第一名队伍 = result_map 中值为 1 的键。
GET
/embed/{slug}/api/results?limit=N
— 最近结果记录
Dragon Tiger
[
{ "round":13463, "daily_round":2280, "date":"2026-05-17",
"dragon":{"suit":"S","value":"4"}, "tiger":{"suit":"C","value":"2"},
"result":"dragon" },
{ "round":13462, "daily_round":2279, "date":"2026-05-17",
"dragon":{"suit":"H","value":"A"}, "tiger":{"suit":"D","value":"9"},
"result":"tiger" },
...
]
最新轮次排在数组前面,最多返回 limit 条。
💡
iframe postMessage 事件:游戏 iframe 在每次阶段变化时向父页面发送消息。
window.addEventListener('message', (e) => {
// e.data.type = 'dragontiger_phase' | 'baccarat_phase' | 'bigsix_phase'
const { type, round, daily_round, phase, remainMs } = e.data;
if (type === 'dragontiger_phase' && phase === 'result') {
// fetch /embed/dragontiger/api/current for card data
}
});
仅在阶段变化时触发,牌数据需在收到此事件后额外调用
/api/current 获取。