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

求基于Node.js API连接React前端的Hyperledger Fabric 2.2示例

Hey there! I totally get your frustration—Hyperledger Fabric 2.x introduced some key changes from 1.4, so older examples often don’t translate cleanly. Let me walk you through a practical setup that connects your Fabric 2.2 network to a React frontend using the Node.js SDK v2.x.

Key Prerequisites First

Make sure you have these in place:

  • Node.js v14+ (compatible with Fabric 2.2 SDK)
  • A running Hyperledger Fabric 2.2 network (with channel, committed chaincode, and enrolled user identities)
  • A React project (use npx create-react-app fabric-react-frontend if you don’t have one)

Step 1: Build a Node.js Middleware (Critical!)

You can’t connect React directly to Fabric from the browser—browsers don’t support the necessary crypto libraries. Instead, create a Node.js backend to handle Fabric interactions, then let React call this backend via APIs.

Setup Backend Project

  1. Initialize a new Node project:

    mkdir fabric-backend && cd fabric-backend
    npm init -y
    npm install fabric-network fabric-ca-client express cors
    
  2. Add your Fabric network’s connection.json (generated when you set up your network) to the project root.

  3. Create the core Fabric connection logic (server.js):

    const { Gateway, Wallets } = require('fabric-network');
    const path = require('path');
    const fs = require('fs');
    const express = require('express');
    const cors = require('cors');
    
    const app = express();
    app.use(cors());
    app.use(express.json());
    
    // Helper: Connect to Fabric network and get chaincode contract
    async function getContract() {
        // Load network configuration
        const ccpPath = path.resolve(__dirname, 'connection.json');
        const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
    
        // Initialize file system wallet (stores user identities)
        const walletPath = path.join(process.cwd(), 'wallet');
        const wallet = await Wallets.newFileSystemWallet(walletPath);
    
        // Verify user identity exists (you'll need to enroll users first)
        const identity = await wallet.get('appUser');
        if (!identity) {
            throw new Error('User "appUser" not found in wallet—enroll them first!');
        }
    
        // Create gateway connection
        const gateway = new Gateway();
        await gateway.connect(ccp, {
            wallet,
            identity: 'appUser',
            discovery: { enabled: true, asLocalhost: true } // Use false for remote networks
        });
    
        // Get channel and chaincode contract
        const network = await gateway.getNetwork('mychannel');
        const contract = network.getContract('mychaincode');
    
        return { contract, gateway };
    }
    
    // API: Query all assets from chaincode
    app.get('/api/assets', async (req, res) => {
        try {
            const { contract, gateway } = await getContract();
            const result = await contract.evaluateTransaction('queryAllAssets');
            await gateway.disconnect();
            res.json(JSON.parse(result.toString()));
        } catch (err) {
            res.status(500).json({ error: err.message });
        }
    });
    
    // API: Create a new asset via chaincode transaction
    app.post('/api/assets', async (req, res) => {
        const { id, value } = req.body;
        try {
            const { contract, gateway } = await getContract();
            await contract.submitTransaction('createAsset', id, value);
            await gateway.disconnect();
            res.json({ message: 'Asset created successfully' });
        } catch (err) {
            res.status(500).json({ error: err.message });
        }
    });
    
    const PORT = 5000;
    app.listen(PORT, () => console.log(`Backend running on http://localhost:${PORT}`));
    

Important: Enroll a User to the Wallet

Before running the backend, you need to enroll a user and store their identity in the wallet. Add a quick script (enrollUser.js) to do this:

const { Wallets } = require('fabric-network');
const FabricCAServices = require('fabric-ca-client');
const path = require('path');
const fs = require('fs');

async function enrollUser() {
    const ccpPath = path.resolve(__dirname, 'connection.json');
    const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));

    // Create CA client
    const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url;
    const ca = new FabricCAServices(caURL);

    // Initialize wallet
    const walletPath = path.join(process.cwd(), 'wallet');
    const wallet = await Wallets.newFileSystemWallet(walletPath);

    // Check if user already exists
    const userExists = await wallet.get('appUser');
    if (userExists) {
        console.log('User "appUser" already exists in wallet');
        return;
    }

    // Enroll admin first (you should have admin credentials in your wallet)
    const adminIdentity = await wallet.get('admin');
    if (!adminIdentity) {
        console.log('Admin identity not found—enroll admin first!');
        return;
    }

    // Get admin signer
    const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type);
    const adminSigner = await provider.getSigner(adminIdentity);

    // Register and enroll appUser
    const secret = await ca.register({
        affiliation: 'org1.department1',
        enrollmentID: 'appUser',
        role: 'client'
    }, adminSigner);

    const enrollment = await ca.enroll({
        enrollmentID: 'appUser',
        enrollmentSecret: secret
    });

    const x509Identity = {
        credentials: {
            certificate: enrollment.certificate,
            privateKey: enrollment.key.toBytes(),
        },
        mspId: 'Org1MSP',
        type: 'X.509',
    };

    await wallet.put('appUser', x509Identity);
    console.log('Successfully enrolled user "appUser" and stored in wallet');
}

enrollUser().catch(err => {
    console.error('Error enrolling user:', err);
    process.exit(1);
});

Run this script once: node enrollUser.js

Step 2: Connect React Frontend to Backend

In your React project, install axios for API calls:

npm install axios

Update src/App.js to interact with the backend:

import { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
    const [assets, setAssets] = useState([]);
    const [newAssetId, setNewAssetId] = useState('');
    const [newAssetValue, setNewAssetValue] = useState('');
    const [error, setError] = useState('');

    // Fetch assets on component mount
    useEffect(() => {
        fetchAssets();
    }, []);

    const fetchAssets = async () => {
        try {
            const response = await axios.get('http://localhost:5000/api/assets');
            setAssets(response.data);
            setError('');
        } catch (err) {
            setError('Failed to load assets: ' + err.message);
        }
    };

    const createAsset = async (e) => {
        e.preventDefault();
        try {
            await axios.post('http://localhost:5000/api/assets', {
                id: newAssetId,
                value: newAssetValue
            });
            setNewAssetId('');
            setNewAssetValue('');
            fetchAssets(); // Refresh assets list
            setError('');
        } catch (err) {
            setError('Failed to create asset: ' + err.message);
        }
    };

    return (
        <div style={{ maxWidth: 800, margin: '0 auto', padding: '2rem' }}>
            <h1>Fabric 2.2 Asset Manager</h1>
            {error && <p style={{ color: 'red' }}>{error}</p>}

            <form onSubmit={createAsset} style={{ marginBottom: '2rem' }}>
                <input
                    type="text"
                    placeholder="Asset ID"
                    value={newAssetId}
                    onChange={(e) => setNewAssetId(e.target.value)}
                    required
                    style={{ marginRight: '1rem', padding: '0.5rem' }}
                />
                <input
                    type="text"
                    placeholder="Asset Value"
                    value={newAssetValue}
                    onChange={(e) => setNewAssetValue(e.target.value)}
                    required
                    style={{ marginRight: '1rem', padding: '0.5rem' }}
                />
                <button type="submit" style={{ padding: '0.5rem 1rem' }}>Create Asset</button>
            </form>

            <h2>Existing Assets</h2>
            <ul style={{ listStyle: 'none', padding: 0 }}>
                {assets.map(asset => (
                    <li key={asset.ID} style={{ padding: '0.5rem', borderBottom: '1px solid #eee' }}>
                        <strong>{asset.ID}</strong>: {asset.Value}
                    </li>
                ))}
            </ul>
        </div>
    );
}

export default App;

Key Differences from Fabric 1.4

  • Gateway API: Fabric 2.x uses the simplified Gateway class instead of the old Client and Channel setup
  • Wallet System: Identities are managed via Wallets (file system, in-memory, etc.) instead of direct keystore paths
  • Chaincode Lifecycle: If you used the 2.x lifecycle (install -> approve -> commit), this setup works seamlessly—no need to adjust for deprecated instantiate calls

Run Everything

  1. Start your Hyperledger Fabric 2.2 network
  2. Run the Node.js backend: node server.js
  3. Run the React frontend: npm start

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:04:29