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

React应用集成PowerBI部署后出现crypto_nonexistent错误的解决方法咨询

React应用集成PowerBI部署后出现crypto_nonexistent错误的解决方法咨询

大家好,我最近在做把PowerBI报表嵌入React应用的需求,参考了微软官方的一个TypeScript示例来实现,但我的项目是纯JavaScript环境。本地在3000端口运行时完全没有问题,但部署到服务器之后,就遇到了这个报错:

Uncaught BrowserAuthError: crypto_nonexistent: The crypto object or function is not available.

我已经尝试了两个修复方案:一是在代码开头添加window.crypto的兼容处理,二是在MSAL配置里把usePkce设为false,但都没能解决问题。

下面是我的关键代码,麻烦大家帮我看看哪里出了问题:

项目入口index.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "./context/AuthProvider";
import { CountryProvider } from "./context/CountryProvider";
import theme from "./theme";
import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { store } from "./store/store";
import * as config from "./pages/powerbi/keys";
import { LogLevel, PublicClientApplication } from "@azure/msal-browser";
import { MsalProvider } from "@azure/msal-react";

// 尝试过的修复代码
if (typeof window !== 'undefined' && !window.crypto) {
  window.crypto = window.msCrypto;
}

const msalInstance = new PublicClientApplication({
  auth: {
      clientId: config.clientId,
      authority: config.authorityUrl,
      redirectUri: "http://{SERVER_IP_ADDRESS}/FOLDER_NAME/"
  },
  cache: {
      cacheLocation: 'localStorage', 
      storeAuthStateInCookie: false,
  },
  system: {
    loggerOptions: {
      loggerCallback: (level, message, containsPii) => {
        console.log(`LEVEL: ${level} MESSAGE: ${message}`);
      },
      piiLoggingEnabled: false,
      logLevel: LogLevel.Verbose
    },
    cryptoOptions: {
      usePkce: false // 尝试过的修复
    }
  }
});

console.log("CRYPTO: ", window.crypto);

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
   <div id="MainDiv">
      <Provider store={store}>
         <BrowserRouter basename="Reactjs_Demo/">
            <AuthProvider>
               <CountryProvider>
                  <ThemeProvider theme={theme}>
                     <MsalProvider instance={msalInstance}>
                     <App />
                     </MsalProvider>
                  </ThemeProvider>
               </CountryProvider>
            </AuthProvider>
         </BrowserRouter>
      </Provider>
   </div>
);

PowerBI嵌入组件代码

import React, { useEffect, useRef, useState, useContext } from "react";
import { AuthenticationResult, InteractionType, EventType, AuthError } from "@azure/msal-browser";
import { MsalContext } from "@azure/msal-react";
import { service, factories, models } from "powerbi-client";
import * as config from "./keys";

const powerbi = new service.Service(factories.hpmFactory, factories.wpmpFactory, factories.routerFactory);

export default function PowerBiReport() {
    const [accessToken, setAccessToken] = useState("");
    const [embedUrl, setEmbedUrl] = useState("");
    const [error, setError] = useState([]);
    const reportRef = useRef(null);
    const context = useContext(MsalContext);

    const authenticate = () => {
        const msalInstance = context.instance;
        const msalAccounts = context.accounts;
        const msalInProgress = context.inProgress;
        const isAuthenticated = context.accounts.length > 0;

        if (error.length > 0) {
            return;
        }

        const eventCallback = msalInstance.addEventCallback((message) => {
            if (message.eventType === EventType.LOGIN_SUCCESS && !accessToken) {
                const payload = message.payload;
                const name = payload.account?.name ? payload.account?.name : "";
                setAccessToken(payload.accessToken);
                setUsername(name);
                tryRefreshUserPermissions();
            }
        });

        const loginRequest = { scopes: config.scopeBase, account: msalAccounts[0] };

        if (!isAuthenticated && msalInProgress === InteractionType.None) {
            msalInstance.loginRedirect(loginRequest);
        } else if (isAuthenticated && accessToken && !embedUrl) {
            getEmbedUrl();
            msalInstance.removeEventCallback(eventCallback);
        } else if (isAuthenticated && !accessToken && !embedUrl && msalInProgress === InteractionType.None) {
            setUsername(msalAccounts[0].name);
            msalInstance.acquireTokenSilent(loginRequest).then((response) => {
                setAccessToken(response.accessToken);
                getEmbedUrl();
            }).catch((error) => {
                if (error.errorCode === "consent_required" || error.errorCode === "interaction_required" || error.errorCode === "login_required") {
                    msalInstance.acquireTokenRedirect(loginRequest);
                } else if (error.errorCode === '429') {
                    setError(["Our Service Token Server (STS) is overloaded, please try again in sometime"]);
                } else {
                    setError(["There was some problem fetching the access token" + error.toString()]);
                }
            });
        }
    };

    const tryRefreshUserPermissions = () => {
        fetch(config.powerBiApiUrl + "v1.0/myorg/RefreshUserPermissions", {
            headers: { "Authorization": "Bearer " + accessToken },
            method: "POST"
        })
        .then(response => {
            if (response.ok) {
                console.log("User permissions refreshed successfully.");
            } else {
                if (response.status === 429) {
                    console.error("Permissions refresh will be available in up to an hour.");
                } else {
                    console.error(response);
                }
            }
        })
        .catch(error => {
            console.error("Failure in making API call." + error);
        });
    };

    const getEmbedUrl = () => {
        fetch(config.powerBiApiUrl + "v1.0/myorg/groups/" + config.wspaceId + "/reports/" + config.reportId, {
            headers: { "Authorization": "Bearer " + accessToken },
            method: "GET"
        })
        .then(response => {
            const errorMessage = ["Error occurred while fetching the embed URL of the report", "Request Id: " + response.headers.get("requestId")];
            response.json()
            .then(body => {
                if (response.ok) {
                    setEmbedUrl(body["embedUrl"]);
                } else {
                    errorMessage.push("Error " + response.status + ": " + body.error.code);
                    setError(errorMessage);
                }
            })
            .catch(() => {
                errorMessage.push("Error " + response.status + ": An error has occurred");
                setError(errorMessage);
            });
        })
        .catch(error => {
            setError([error]);
        });
    };

    const setUsername = (username) => {
        const welcome = document.getElementById("welcome");
        if (welcome !== null) welcome.innerText = "Welcome, " + username;
    };

    useEffect(() => {
        if (reportRef.current !== null) {
            const reportContainer = reportRef.current;
            if (error.length) {
                reportContainer.textContent = "";
                error.forEach(line => {
                    reportContainer.appendChild(document.createTextNode(line));
                    reportContainer.appendChild(document.createElement("br"));
                });
            } else if (accessToken !== "" && embedUrl !== "") {
                const embedConfiguration = {
                    type: "report",
                    tokenType: models.TokenType.Aad,
                    accessToken,
                    embedUrl,
                    id: config.reportId,
                };
                const report = powerbi.embed(reportContainer, embedConfiguration);
                report.off("loaded");
                report.on("loaded", () => {
                    console.log("Report load successful");
                });
                report.off("rendered");
                report.on("rendered", () => {
                    console.log("Report render successful");
                });
                report.off("error");
                report.on("error", (event) => {
                    const errorMsg = event.detail;
                    console.error(errorMsg);
                });
            }
        }
    }, [accessToken, embedUrl, error]);

    useEffect(() => {
        authenticate();
    }, []);

    useEffect(() => {
        return () => {
            if (reportRef.current) {
                powerbi.reset(reportRef.current);
            }
        };
    }, []);

    return (
        <div>
            <div id="welcome"></div>
            <div ref={reportRef}>
                Loading the report...
            </div>
        </div>
    );
};

我的项目是用CRA(Create React App)创建的,有没有大佬能帮我分析下这个问题怎么解决呀?

备注:内容来源于stack exchange,提问作者Mahmud Mridul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:49:31