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

开发类MetaMask扩展时,无法向PancakeSwap返回响应的问题

开发类MetaMask浏览器扩展时的响应返回问题

我正在开发一款类似MetaMask的浏览器扩展,使用@metamask/providers库向网页注入provider。目前能接收PancakeSwap的JSON RPC请求,用json-rpc-engine处理后,无法将响应返回给网站完成连接流程,试过window.postMessage和metamaskStream.write(data)都无效。


注入页面(inpage)代码

import { WindowPostMessageStream } from "@metamask/post-message-stream";
import { initializeProvider } from "@metamask/providers/dist/initializeInpageProvider";

// contexts
const CONTENT_SCRIPT = "contentscript";
const INPAGE = "inpage";

// setup background connection
const metamaskStream = new WindowPostMessageStream({
  name: INPAGE,
  target: CONTENT_SCRIPT,
});

initializeProvider({
  connectionStream: metamaskStream,
});

后台(background.js)注入代码

chrome.scripting.registerContentScripts([
      {
        id: "contentscript",
        matches: ["file://*/*", "http://*/*", "https://*/*"],
        js: ["inpage-bundle.js"],
        runAt: "document_start",
        world: "MAIN",
        allFrames: true,
      },
    ]);

内容脚本(content script)代码

/*global chrome*/
import { WindowPostMessageStream } from "@metamask/post-message-stream";
import { metamaskStream, provider } from "./inpage";
const Buffer = require("safe-buffer").Buffer;

const isManifestV3 = true;
// contexts
const CONTENT_SCRIPT = "contentscript";
const INPAGE = "inpage";

const setupPageStreams = () => {
  // the transport-specific streams for communication between inpage and background
  const pageStream = new WindowPostMessageStream({
    name: CONTENT_SCRIPT,
    target: INPAGE,
  });

  if (isManifestV3) {
    pageStream.on("data", async ({ data }) => {
      console.log(data);
      if (data) {
        if (data.method === "eth_requestAccounts") {
          const finalResponse = await new Promise((resolve, reject) => {
            chrome.runtime.sendMessage(
              { type: "JSON-RPC", payload: data },
              (response) => {
                console.log(response, "response");
                if (chrome.runtime.lastError) {
                  reject(chrome.runtime.lastError);
                } else if (response && response.type === "JSON-RPC") {
                  resolve(response.payload);
                } else {
                  reject(new Error("Invalid response received"));
                }
              }
            );
          });

          if (finalResponse) {
            const responseToSend = {
              ...finalResponse,
              namespace: "global",
              code: 0,
              message: "SUCCESS",
            };

            console.log("finalResponse", responseToSend);
            pageStream.write(responseToSend);
          }
        }
      }
    });
  }
};

/**
 * Initializes two-way communication streams between the browser extension and
 * the local per-page browser context. This function also creates an event listener to
 * reset the streams if the service worker resets.
 */
const initStreams = () => {
  setupPageStreams();
};

const start = () => {
  initStreams();
};

start();

问题分析与修复方案

1. 响应格式不符合JSON-RPC规范

@metamask/providers要求响应必须严格遵循JSON-RPC 2.0规范,你当前添加的namespace、code、message自定义字段会导致inpage provider无法识别响应。需要移除这些额外字段,保留标准结构:

// 直接使用后台返回的标准响应,移除自定义字段
const responseToSend = finalResponse;

2. 确保响应ID与请求匹配

JSON-RPC要求响应的id必须和对应请求的id一致,否则网页端会忽略响应。检查后台返回的finalResponse是否携带请求的id,如果没有,手动补充:

const responseToSend = {
  jsonrpc: "2.0",
  id: data.id, // 从原始请求中获取ID
  result: finalResponse.result,
};

3. 对齐流的消息结构

inpage端接收的请求是{ data: ... }格式,返回响应时需要保持相同的结构,否则流无法正确解析:

pageStream.write({ data: responseToSend });

4. 完善错误处理

如果请求处理失败,需要返回标准JSON-RPC错误响应,避免静默失败:

pageStream.on("data", async ({ data }) => {
  console.log(data);
  if (data?.method === "eth_requestAccounts") {
    try {
      const finalResponse = await new Promise((resolve, reject) => {
        chrome.runtime.sendMessage(
          { type: "JSON-RPC", payload: data },
          (response) => {
            if (chrome.runtime.lastError) {
              reject(chrome.runtime.lastError);
            } else if (response?.type === "JSON-RPC") {
              resolve(response.payload);
            } else {
              reject(new Error("Invalid response received"));
            }
          }
        );
      });

      const responseToSend = {
        jsonrpc: "2.0",
        id: data.id,
        result: finalResponse.result,
      };
      pageStream.write({ data: responseToSend });
    } catch (error) {
      const errorResponse = {
        jsonrpc: "2.0",
        id: data.id,
        error: {
          code: -32000,
          message: error.message,
        },
      };
      pageStream.write({ data: errorResponse });
    }
  }
});

5. 确认流的初始化配置

确保content script中的pageStream和inpage中的metamaskStream的name、target完全对应,避免通信方向错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:17:05