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

本地运行HTML&JavaScript遇错误:TypeError: 'openai'模块无法解析为有效URL

问题解决:浏览器无法解析openai模块导入

错误原因

你当前的代码把Node.js环境的模块导入逻辑直接放到浏览器端运行了。浏览器的ES模块系统要求导入的资源必须是完整的相对/绝对URL,而npm安装的openai模块是为Node.js设计的,浏览器无法识别import OpenAI from 'openai'这种写法,会把它当成无效URL抛出错误。

另外,Scrimba环境内置了模块打包工具(比如Webpack),会自动把npm模块转换为浏览器能识别的代码,所以教程里的写法在那里能运行,但本地直接用Express静态服务做不到这一点。


解决方案

方案1:使用OpenAI浏览器端SDK(快速测试用,不推荐生产环境)

这种方式适合快速验证功能,但会暴露你的API密钥,绝对不能用于公开上线的项目:

  1. 修改index.html,添加OpenAI浏览器版的CDN引入:
<!-- 在你的现有script标签之前添加 -->
<script src="https://cdn.jsdelivr.net/npm/openai@4.0.0/dist/browser/index.min.js"></script>
<script type="module" src="index.js"></script>
  1. 修改index.js:
    • 删除import OpenAI from 'openai'和import process from './env.js'这两行
    • 初始化OpenAI时手动传入API密钥,并启用浏览器端允许选项:
// 替换原来的openai初始化代码
const openai = new OpenAI({
  apiKey: '你的OpenAI API密钥',
  dangerouslyAllowBrowser: true // 必须设置这个才能在浏览器里运行
});

// 其余交互代码保留不变
const setupTextarea = document.getElementById("setup-textarea");
// ... 剩下的代码

方案2:后端代理(推荐,安全合规)

这是生产环境的标准做法,通过自己的Express后端中转请求,避免API密钥暴露:

步骤1:改造后端(server.js)

import express from 'express';
import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();

const app = express();
// 解析JSON请求体
app.use(express.json());
// 托管前端静态文件(假设你的index.html、index.js在public文件夹下)
app.use(express.static('public'));

// 初始化OpenAI(用环境变量存密钥,安全)
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

// 新增接口,处理前端的OpenAI请求
app.post('/api/chat', async (req, res) => {
  try {
    const completion = await openai.chat.completions.create({
      messages: req.body.messages,
      model: "gpt-3.5-turbo",
    });
    res.json(completion);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000, () => console.log('服务运行在 http://localhost:3000'));

步骤2:创建环境变量文件

在项目根目录新建.env文件,写入你的API密钥:

OPENAI_API_KEY=你的OpenAI密钥

注意:不要把.env文件提交到Git仓库,在.gitignore里添加.env。

步骤3:改造前端index.js

删除所有OpenAI相关的导入和初始化代码,把fetchBotReply改成调用自己的后端接口:

const setupTextarea = document.getElementById("setup-textarea");
const setupInputContainer = document.getElementById("setup-input-container");
const movieBossText = document.getElementById("movie-boss-text");

document.getElementById("send-btn").addEventListener("click", () => {
  const userInput = setupTextarea.value;
  setupInputContainer.innerHTML =
      `<img src="images/loading.svg" class="loading" id="loading">`;
  movieBossText.innerText =
      `Ok, just wait a second while my digital brain digests that...`;

  fetchBotReply(userInput)
});

async function fetchBotReply(userInput) {
  const response = await fetch('/api/chat', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      messages: [
        {role: "system", content: "You are a helpful assistant."},
        {role: "user", content: userInput} // 用用户输入替换固定内容
      ]
    })
  });
  const data = await response.json();
  console.log(data.choices[0]);
  // 这里可以把结果渲染到页面上
  movieBossText.innerText = data.choices[0].message.content;
  setupInputContainer.innerHTML = `<textarea id="setup-textarea"></textarea><button id="send-btn">Send</button>`;
}

关键提醒

  • 永远不要在前端代码里直接写API密钥,任何人都能通过浏览器开发者工具看到,会导致你的OpenAI账号被滥用、产生高额费用。
  • 后端代理方案不仅安全,还能帮你做请求限流、日志记录等额外功能,是工业界的标准做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:00:34