美文网首页Dapp开发
IPFS + Ethereum(上篇):JS+IPFS-API存

IPFS + Ethereum(上篇):JS+IPFS-API存

作者: yuyangray | 来源:发表于2018-04-22 16:06 被阅读140次

    1. 内容简介

    这篇文章将为大家讲解js-ipfs-api的简单使用,如何将数据上传到IPFS,以及如何从IPFS通过HASH读取数据。

    2. IPFS-HTTP效果图

    3. 实现步骤

    3.1 安装create-react-app

    参考文档:https://reactjs.org/tutorial/tutorial.html

    yuyangdeMacBook-Pro:~ yuyang$ npm install -g create-react-app
    /Users/yuyang/.nvm/versions/node/v8.9.4/bin/create-react-app -> /Users/yuyang/.nvm/versions/node/v8.9.4/lib/node_modules/create-react-app/index.js
    + create-react-app@1.5.2
    added 67 packages in 14.512s
    

    3.2 React项目创建

    yuyangdeMacBook-Pro:~ yuyang$ create-react-app ipfs-http-demo
    
    Creating a new React app in /Users/yuyang/ipfs-http-demo.
    
    Installing packages. This might take a couple of minutes.
    Installing react, react-dom, and react-scripts...
    
    ... ... 
    
    Success! Created ipfs-http-demo at /Users/yuyang/ipfs-http-demo
    Inside that directory, you can run several commands:
    
      yarn start
        Starts the development server.
    
      yarn build
        Bundles the app into static files for production.
    
      yarn test
        Starts the test runner.
    
      yarn eject
        Removes this tool and copies build dependencies, configuration files
        and scripts into the app directory. If you do this, you can’t go back!
    
    We suggest that you begin by typing:
    
      cd ipfs-http-demo
      yarn start
    
    Happy hacking!
    

    3.3 运行React项目

    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ npm start
    
    Compiled successfully!
    
    You can now view ipfs-http-demo in the browser.
    
      Local:            http://localhost:3000/
      On Your Network:  http://192.168.0.4:3000/
    
    Note that the development build is not optimized.
    To create a production build, use yarn build.
    

    3.4 浏览项目

    浏览器会自动打开:http://localhost:3000/

    效果如下:

    3.5 安装ipfs-api

    https://www.npmjs.com/package/ipfs-api

    项目结构

    安装ipfs-api

    切换到项目根目录,安装ipfs-api

    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ npm install --save ipfs-api
    
    

    ipfs-api安装完后,如上图所示,接下来刷新一下浏览器,看看项目是否有问题,正常来讲,一切会正常。

    3.6 完成UI逻辑

    拷贝下面的代码,将src/App.js里面的代码直接替换掉。

    import React, { Component } from 'react';
    import './App.css';
    
    class App extends Component {
    
    
          constructor(props) {
              super(props);
              this.state = {
                strHash: null,
                strContent: null
              }
          }
    
        render() {
          return (
            <div className="App">
              <input
                ref="ipfsContent"
               />
              <button onClick={() => {
                let ipfsContent = this.refs.ipfsContent.value;
                console.log(ipfsContent);
              }}>提交到IPFS</button>
    
              <p>{this.state.strHash}</p>
    
              <button onClick={() => {
                console.log('从ipfs读取数据。')
               }}>读取数据</button>
               <h1>{this.state.strContent}</h1>
            </div>
          );
        }
    }
    
    export default App;
    

    上面的代码完成的工作是,当我们在输入框中输入一个字符串时,点击提交到IPFS按钮,将文本框中的内容取出来打印,后续我们需要将这个数据上传到IPFS。点击读取数据按钮,我们也只是随便打印了一个字符串,后面需要从IPFS读取数据,然后将读取的数据存储到状态机变量strContent中并且展示出来。

    现在刷新网页,输入内容,点击提交到IPFS,Console打印出输入的内容。点击读取数据,Console打印出从ipfs读取数据。

    3.7 导入IPFS

    const ipfsAPI = require('ipfs-api');
    const ipfs = ipfsAPI({host: 'localhost', port: '5001', protocol: 'http'});
    

    3.8 编写上传大文本字符串到IPFS的Promise函数

    saveTextBlobOnIpfs = (blob) => {
        return new Promise(function(resolve, reject) {
          const descBuffer = Buffer.from(blob, 'utf-8');
          ipfs.add(descBuffer).then((response) => {
            console.log(response)
            resolve(response[0].hash);
          }).catch((err) => {
            console.error(err)
            reject(err);
          })
        })
      }
    

    response[0].hash返回的是数据上传到IPFS后返回的HASH字符串。

    3.9 上传数据到IPFS

    this.saveTextBlobOnIpfs(ipfsContent).then((hash) => {
        console.log(hash);
        this.setState({strHash: hash});
    });
    

    ipfsContent是从文本框中取到的数据,调用this.saveTextBlobOnIpfs方法将数据上传后,会返回字符串hash,并且将hash存储到状态机变量strHash中。

    目前完整的代码:

    import React, {Component} from 'react';
    import './App.css';
    
    const ipfsAPI = require('ipfs-api');
    const ipfs = ipfsAPI({host: 'localhost', port: '5001', protocol: 'http'});
    
    class App extends Component {
    
      constructor(props) {
        super(props);
        this.state = {
          strHash: null,
          strContent: null
        }
      }
    
      saveTextBlobOnIpfs = (blob) => {
        return new Promise(function(resolve, reject) {
          const descBuffer = Buffer.from(blob, 'utf-8');
          ipfs.add(descBuffer).then((response) => {
            console.log(response)
            resolve(response[0].hash);
          }).catch((err) => {
            console.error(err)
            reject(err);
          })
        })
      }
    
      render() {
        return (<div className="App">
          <input ref="ipfsContent" />
          <button onClick={() => {
              let ipfsContent = this.refs.ipfsContent.value;
              console.log(ipfsContent);
              this.saveTextBlobOnIpfs(ipfsContent).then((hash) => {
                console.log(hash);
                this.setState({strHash: hash});
              });
            }}>提交到IPFS</button>
    
          <p>{this.state.strHash}</p>
    
          <button onClick={() => {
              console.log('从ipfs读取数据。')
            }}>读取数据</button>
          <h1>{this.state.strContent}</h1>
        </div>);
      }
    }
    
    export default App;
    

    3.10 跨域资源共享CORS配置

    跨域资源共享( CORS )配置,依次在终端执行下面的代码:

    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST", "OPTIONS"]'
    
    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]'
    
    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials '["true"]'
    
    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Headers '["Authorization"]'
    
    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs config --json API.HTTPHeaders.Access-Control-Expose-Headers '["Location"]'
    

    用正确的端口运行daemon:

    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs config Addresses.API
    /ip4/127.0.0.1/tcp/5001
    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs config Addresses.API /ip4/127.0.0.1/tcp/5001
    yuyangdeMacBook-Pro:ipfs-http-demo yuyang$ ipfs daemon
    

    3.11 刷新网页提交数据并在线查看数据

    上传数据,并且查看返回hash值

    在线查看上传到IPFS的数据

    http://ipfs.io/ipfs/QmejvEPop4D7YUadeGqYWmZxHhLc4JBUCzJJHWMzdcMe2y

    3.12 从IPFS读取数据

    ipfs.cat(this.state.strHash).then((stream) => {
        console.log(stream);
        let strContent = Utf8ArrayToStr(stream);
        console.log(strContent);
        this.setState({strContent: strContent});
    });
    

    streamUint8Array类型的数据,下面的方法是将Uint8Array转换为string字符串。

    Utf8ArrayToStr

    function Utf8ArrayToStr(array) {
        var out, i, len, c;
        var char2, char3;
    
        out = "";
        len = array.length;
        i = 0;
        while(i < len) {
        c = array[i++];
        switch(c >> 4)
          {
            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
              // 0xxxxxxx
              out += String.fromCharCode(c);
              break;
            case 12: case 13:
              // 110x xxxx   10xx xxxx
              char2 = array[i++];
              out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
              break;
            case 14:
              // 1110 xxxx  10xx xxxx  10xx xxxx
              char2 = array[i++];
              char3 = array[i++];
              out += String.fromCharCode(((c & 0x0F) << 12) |
                             ((char2 & 0x3F) << 6) |
                             ((char3 & 0x3F) << 0));
              break;
            default:
              break;
          }
        }
    
        return out;
    }
    

    完整源码

    import React, {Component} from 'react';
    import './App.css';
    
    const ipfsAPI = require('ipfs-api');
    const ipfs = ipfsAPI({host: 'localhost', port: '5001', protocol: 'http'});
    
    function Utf8ArrayToStr(array) {
      var out,
        I,
        len,
        c;
      var char2,
        char3;
    
      out = "";
      len = array.length;
      i = 0;
      while (i < len) {
        c = array[i++];
        switch (c >> 4) {
          case 0:
          case 1:
          case 2:
          case 3:
          case 4:
          case 5:
          case 6:
          case 7:
            // 0xxxxxxx
            out += String.fromCharCode(c);
            break;
          case 12:
          case 13:
            // 110x xxxx   10xx xxxx
            char2 = array[i++];
            out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
            break;
          case 14:
            // 1110 xxxx  10xx xxxx  10xx xxxx
            char2 = array[i++];
            char3 = array[i++];
            out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
            break;
          default:
            break;
        }
      }
    
      return out;
    }
    
    class App extends Component {
    
      constructor(props) {
        super(props);
        this.state = {
          strHash: null,
          strContent: null
        }
      }
    
      saveTextBlobOnIpfs = (blob) => {
        return new Promise(function(resolve, reject) {
          const descBuffer = Buffer.from(blob, 'utf-8');
          ipfs.add(descBuffer).then((response) => {
            console.log(response)
            resolve(response[0].hash);
          }).catch((err) => {
            console.error(err)
            reject(err);
          })
        })
      }
    
      render() {
        return (<div className="App">
          <input ref="ipfsContent" />
          <button onClick={() => {
              let ipfsContent = this.refs.ipfsContent.value;
              console.log(ipfsContent);
              this.saveTextBlobOnIpfs(ipfsContent).then((hash) => {
                console.log(hash);
                this.setState({strHash: hash});
              });
            }}>提交到IPFS</button>
    
          <p>{this.state.strHash}</p>
    
          <button onClick={() => {
              console.log('从ipfs读取数据。')
              ipfs.cat(this.state.strHash).then((stream) => {
                console.log(stream);
                let strContent = Utf8ArrayToStr(stream);
                console.log(strContent);
                this.setState({strContent: strContent});
              });
            }}>读取数据</button>
          <h1>{this.state.strContent}</h1>
        </div>);
      }
    }
    
    export default App;
    

    4. 总结

    这篇文章主要讲解如何配置React环境,如何创建React项目,如何安装js-ipfs-api,如何上传数据,如何设置开发环境,如何下载数据等等内容。通过这篇文章的系统学习,你会掌握js-ipfs-api在项目中的使用流程。

    参考:【IPFS + 区块链 系列】 入门篇 - IPFS + Ethereum (上篇)-js-ipfs-api
    作者:黎跃春

    相关文章

      网友评论

      • 73af3583159b:你好,请问你觉得如果将音乐数据上传到IPFS网络,可行吗?如果可以的话,是如何存储的呢,谢谢,能否给点建议

      本文标题:IPFS + Ethereum(上篇):JS+IPFS-API存

      本文链接:https://www.haomeiwen.com/subject/dgfclftx.html