Crypto.randomUUID() 不适用于 Next.js v13

问题描述 投票:0回答:4

环境

Next.js v13稳定,无 ./app 文件夹)在 Ubuntu WSL 中与 Node v18 一起运行。

根据 de docs ,Crypto API 自 Node v14~ish 起就已存在。

这确实已经在我的环境中的 Node 中进行了测试: Node 18 importing and running crypto.randomUUID() 我还打印了整个对象,它看起来就像文档所说的那样。

问题

想象一下这个简单的组件:

import crypto from 'crypto';

export default function Crypto() {
  console.log(crypto);

  return (
    <p>
      {crypto.randomUUID()}
    </p>
  );
}

Next.js 表示“在 397 毫秒内成功编译了客户端和服务器”。但在 UUID 在浏览器中渲染几毫秒后,Next.js 会抛出一些与 randomUUID 不是函数有关的错误。

Next Runtime Error with crypto.randomUUID()

我发现 Webpack 有点混杂在那里;没试过Turbopack。这超出了这个问题的范围。

注释掉段落中的方法调用后,console.log(crypto) 像往常一样在开发工具中运行并打印两次,如下所示: crypto method printed

注意一个来自“react devetools backend”,另一个来自 webkpack。这让我相信错误会在服务器端抛出,因为 console.loglog 在 UUID 方法之前被调用。

服务器端,尽管浏览器中抛出错误,Next CLI 仍会打印该对象,并且它包含方法:Next CLI prints crypto object and randomUUID is listed

客户端,在打印的对象中,找不到 randomUUID() 方法: Inside printed crypto object in devtools 这确认了错误消息。我的代码无法访问该方法。此外,与 Node 文档相比,还缺少一些方法。

然而,如果直接来自 devTools

console.log(crypto)
,它的原型中确实有该方法:

randomUUID directly from devtools

此外,由于结构的原因,我倾向于相信正在打印的加密对象在某种程度上来自 Node,因为 Chrome V8 加密对象的结构完全不同。但到底为什么这些方法不见了呢?

我尝试在服务器端、客户端和中间使用 console.loging 对象。不知何故,该方法在中间丢失了。 Webpack 可能是罪魁祸首。最糟糕的是,尽管只是一眨眼的功夫,我就可以在抛出错误之前看到渲染的字符串;忽略错误卡会引发空白正文。字符串消失。

编辑 导入/需要加密的原因是它可以在 Node.js 中运行。接下来是SSR框架;简而言之,它首先在服务器上运行,尽可能地以 HTML 形式呈现并交付给客户端。如果未导入,当 Next 尝试调用 Crypto 服务器端时,Node 会抛出错误。

现在,我告诉这段代码仅在 Window 对象可用时运行(即我在浏览器中)并且它与本机 chromium V8 Crypto 对象一起运行。

// import crypto from 'crypto';

export default function Crypto() {
  if (typeof window !== 'undefined') {
    console.log('CLIENT: ', crypto.randomUUID());

    return (
      <p>
        {crypto.randomUUID()}
      </p>
    );
  }

  return (
    <h1>SERVER SIDE</h1>
  );
}

唯一的缺点是,不知怎的,still在Next magic中运行了两次,一次是服务器端,一次是客户端,这意味着它不是React 18的bc。它准确地告诉我,是预期的UUID 函数总是返回不同的结果。

node.js reactjs next.js
4个回答
2
投票

我在尝试创建一个可以在 NextJS 应用程序和非服务器端渲染的 Storybook 中使用的组件时遇到了同样的问题。 我最终在渲染中调用了这个 polyfill :

import * as cryptoServer from "crypto";
function getRandomUUID(){

    if (typeof window === "undefined"){
        return cryptoServer.randomBytes(16).toString('hex')
    }
    return crypto.randomUUID();
}

我没有收到来自 vite 的关于导入加密模块的投诉


0
投票

浏览器不在安全上下文中运行时限制对某些加密 API 的访问(如此处定义)。


0
投票

当页面最初加载时,将其设置为

useEffect
钩子中的状态,以便它持续存在,然后从状态渲染它。

const Crypto = () => {
 const [randomUUID, setRandomUUID] = useState();

 useEffect((
  if (typeof window !== 'undefined' && !randomUUID) {
   setRandomUUID(crypto.randomUUID());
  }
 ),[]);

 if(!randomUUID) <>No UUID</>;
 return <>{randomUUID}</>
}

export default Crypto;

0
投票

我在带有 NestJS 和 Next.js 的 monorepo 设置中使用名为 createUUID 的库。最近,将Next.js更新到v14.1后,遇到错误:crypto.randomUUID不是函数。 Next.js 中间件的运行时环境似乎已经改变。修改以下代码解决了该问题:

interface CryptoType {
  randomUUID: () => string;
}

let cryptoUtil: CryptoType;

// for browser
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
  cryptoUtil = crypto as unknown as CryptoType;
} else {
  // https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation#importing-runtime-specific-code

  // for next edge runtime
  if (process.env.NEXT_RUNTIME === 'edge') {
    cryptoUtil = crypto as unknown as CryptoType;
    // for next nodejs runtime
  } else if (process.env.NEXT_RUNTIME === 'nodejs') {
    const nodeCrypto = require('crypto');
    cryptoUtil = {
      randomUUID: () => nodeCrypto.randomUUID(),
    };
    // for others (maybe server)
  } else {
    const nodeCrypto = require('crypto');
    cryptoUtil = {
      randomUUID: () => nodeCrypto.randomUUID(),
    };
  }
}

export function createUUID() {
  return cryptoUtil.randomUUID().replace(/-/g, '');
}
© www.soinside.com 2019 - 2024. All rights reserved.