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

Emscripten_fetch POST请求返回值始终为0的问题排查及可用EM_JS版本实现示例需求

问题分析与解决方案

1. emscripten_fetch是否支持携带请求头的POST请求?

当然支持,emscripten_fetch完全兼容带自定义请求头的POST请求。你遇到的Uncaught TypeError: XMLHttpRequest.open: Cannot convert argument 1 to ByteString错误,核心原因不是API不支持,而是requestMethod字段的内存被意外污染了——错误提示里的字符值56770远超出ASCII范围,说明原本的"POST"字符串被破坏了。

给你几个排查和修复的方向:

  • 检查attr变量的作用域:如果attr是栈上的局部变量,要确保后续代码没有溢出覆盖这块内存(比如其他局部变量越界、指针操作错误等)。
  • 替换strcpy为更安全的strncpy,避免字符串拷贝越界:
    strncpy(attr.requestMethod, "POST", EMSCRIPTEN_FETCH_REQUEST_METHOD_SIZE - 1);
    attr.requestMethod[EMSCRIPTEN_FETCH_REQUEST_METHOD_SIZE - 1] = '\0'; // 手动确保字符串结尾
    
  • 验证request变量的合法性:确认request.c_str()返回的是有效、以NULL结尾的字符串,没有包含非法字符。

另外,你的等待循环可以简化,直接用INFINITY参数让emscripten_fetch_wait一直等待请求完成,不用手动循环判断超时:

EMSCRIPTEN_RESULT ret = emscripten_fetch_wait(fetch, INFINITY);
if (ret != EMSCRIPTEN_SUCCESS) {
    qDebug("Fetch operation failed with error code: %d", ret);
    emscripten_fetch_close(fetch);
    return; // 提前处理错误
}

2. EM_JS版本POST请求实现示例

下面给你两个实用的EM_JS实现:一个是推荐的异步回调版本(避免阻塞主线程),另一个是同步版本(匹配你之前的waitable使用习惯)。

异步回调版本(推荐)

这个版本用JavaScript的fetch API发送请求,通过回调函数把结果传回C++,不用你手动处理Promise:

#include <emscripten.h>
#include <string>

// 定义回调函数类型:接收响应数据和状态码
typedef void (*FetchCallback)(const char* responseData, int statusCode);

// 声明EM_JS函数
extern "C" {
    EM_JS(void, js_post_request, (const char* url, const char* jsonData, FetchCallback callback), {
        // 把C字符串转成JS字符串
        const urlStr = UTF8ToString(url);
        const dataStr = UTF8ToString(jsonData);
        
        fetch(urlStr, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: dataStr,
        })
        .then(response => Promise.all([response.status, response.text()]))
        .then(([status, data]) => {
            // 把结果传给C++回调
            callback(data, status);
        })
        .catch(error => {
            // 请求失败时传递错误信息
            callback(error.toString(), 0);
        });
    });
}

// 回调函数实现
void handleFetchResponse(const char* data, int status) {
    if (status == 200) {
        qDebug("Request succeeded! Response: %s", data);
        // 在这里处理返回的JSON数据
    } else {
        qDebug("Request failed! Status: %d, Error: %s", status, data);
    }
}

// 发起请求的示例函数
void sendPostRequest(const std::string& url, const std::string& jsonData) {
    js_post_request(url.c_str(), jsonData.c_str(), handleFetchResponse);
}

同步版本(仅必要时使用)

如果需要和你之前的同步等待逻辑一致,可以用XMLHttpRequest的同步模式,但注意这个会阻塞浏览器主线程,可能导致页面卡顿:

#include <emscripten.h>
#include <string>

extern "C" {
    EM_JS(const char*, js_post_request_sync, (const char* url, const char* jsonData, int* outStatus), {
        const urlStr = UTF8ToString(url);
        const dataStr = UTF8ToString(jsonData);
        const xhr = new XMLHttpRequest();
        
        // 第三个参数设为false表示同步请求
        xhr.open('POST', urlStr, false);
        xhr.setRequestHeader('Content-Type', 'application/json');
        
        try {
            xhr.send(dataStr);
            *outStatus = xhr.status;
            // 分配内存存储响应内容,C++侧需要手动释放
            return allocateUTF8(xhr.responseText);
        } catch (error) {
            *outStatus = 0;
            return allocateUTF8(error.toString());
        }
    });
}

// 同步请求示例函数
std::string sendSyncPost(const std::string& url, const std::string& jsonData) {
    int status = 0;
    const char* response = js_post_request_sync(url.c_str(), jsonData.c_str(), &status);
    std::string result(response);
    
    // 释放EM_JS分配的内存,避免泄漏
    emscripten_free(const_cast<char*>(response));
    
    if (status == 200) {
        qDebug("Sync request succeeded!");
    } else {
        qDebug("Sync request failed, status code: %d", status);
    }
    return result;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 15:08:15