You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何可靠获取sendBeacon发起页面URL并安全传递至后端?

可靠传递sendBeacon请求发起页面pathname的方案

由于前端所有数据都存在被篡改的可能,核心思路是通过后端验证机制来确保传递的pathname可信,以下是几种可行方案:

方案1:后端生成带签名的页面标识

页面加载时由后端为当前pathname生成加密签名,前端同时传递pathname和签名,后端通过重新计算签名验证数据真实性。

后端实现示例(以Python为例)

import hmac
import hashlib
from flask import Flask, request, render_template

app = Flask(__name__)
SECRET_KEY = "your-secure-secret-key"  # 务必使用安全的密钥,避免硬编码

@app.route('/page')
def render_page():
    current_path = request.path
    # 生成HMAC签名
    signature = hmac.new(
        SECRET_KEY.encode(),
        current_path.encode(),
        hashlib.sha256
    ).hexdigest()
    # 将签名传递到前端页面,比如通过meta标签
    return render_template('your-page.html', path_signature=signature)

前端实现

<!-- 在页面的head中添加meta标签 -->
<meta name="path-signature" content="{{ path_signature }}">
const url = "/some/url";
const data = new FormData();
const pathname = window.location.pathname;
const signature = document.querySelector('meta[name="path-signature"]').content;

data.append("pathname", pathname);
data.append("signature", signature);
navigator.sendBeacon(url, data);

后端验证逻辑

当接收到sendBeacon请求时,重新计算传入pathname的签名,与前端传递的signature对比:

@app.route('/some/url', methods=['POST'])
def receive_beacon():
    pathname = request.form.get('pathname')
    received_signature = request.form.get('signature')
    # 重新计算签名
    computed_signature = hmac.new(
        SECRET_KEY.encode(),
        pathname.encode(),
        hashlib.sha256
    ).hexdigest()
    # 验证签名是否一致
    if received_signature == computed_signature:
        # 签名有效,pathname可信
        process_pathname(pathname)
        return '', 204
    else:
        # 签名无效,数据可能被篡改
        return '', 403

方案2:利用Session关联页面路径

用户访问页面时,后端将当前pathname存入用户Session,前端sendBeacon时仅传递Session标识(通常由Cookie自动携带),后端通过Session直接获取可信的pathname。

后端实现示例

@app.route('/page')
def render_page():
    # 将当前路径存入Session
    session['current_path'] = request.path
    return render_template('your-page.html')

@app.route('/some/url', methods=['POST'])
def receive_beacon():
    # 从Session中获取可信的pathname
    trusted_pathname = session.get('current_path')
    if trusted_pathname:
        process_pathname(trusted_pathname)
        return '', 204
    else:
        return '', 400

前端实现

无需额外传递pathname,直接发送请求即可:

const url = "/some/url";
const data = new FormData();
// 可添加其他业务数据,pathname由后端从Session获取
navigator.sendBeacon(url, data);

注意:该方案需考虑多标签页场景,若用户打开多个页面,Session中会存储最后访问的路径,需根据业务需求判断是否适用。

方案3:页面唯一ID映射

后端渲染页面时生成唯一ID,将ID与对应pathname存储在数据库/缓存中,前端sendBeacon时传递该ID,后端通过ID查询获取可信的pathname。

后端实现示例

import uuid
from flask import Flask, request, render_template
from redis import Redis

app = Flask(__name__)
redis = Redis(host='localhost', port=6379, db=0)

@app.route('/page')
def render_page():
    current_path = request.path
    page_id = str(uuid.uuid4())
    # 将page_id与pathname存入Redis,设置过期时间(比如1小时)
    redis.setex(page_id, 3600, current_path)
    return render_template('your-page.html', page_id=page_id)

前端实现

<input type="hidden" id="page-id" value="{{ page_id }}">
const url = "/some/url";
const data = new FormData();
const pageId = document.getElementById('page-id').value;

data.append("page_id", pageId);
navigator.sendBeacon(url, data);

后端查询逻辑

@app.route('/some/url', methods=['POST'])
def receive_beacon():
    page_id = request.form.get('page_id')
    trusted_pathname = redis.get(page_id)
    if trusted_pathname:
        process_pathname(trusted_pathname.decode())
        return '', 204
    else:
        return '', 400

内容的提问来源于stack exchange,提问作者pileup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 22:48:28