【IPFS + 區塊鏈 系列】 入門篇 - IPFS + Ethereum (上篇)-js-ipfs-api

做者:黎躍春,孔壹學院創始人,區塊鏈、高可用架構師css

微信:liyc1215html

區塊鏈博客:http://liyuechun.org前端

Ebay項目

基於以太坊Ethereum & IPFS的去中心化Ebay區塊鏈項目詳情連接node

目錄

1. 內容簡介

在前面兩篇文章中,第一篇春哥給你們詳細介紹了IPFS環境配置,第二篇介紹了IPFS如何搭建我的博客,經過這兩篇文章相信你們已經對IPFS有所瞭解,接下來的這篇文章,咱們將爲你們講解js-ipfs-api的簡單使用,如何將數據上傳到IPFS,以及如何從IPFS經過HASH讀取數據。npm

2. IPFS-HTTP效果圖

3. 實現步驟

3.1 安裝create-react-app

參考文檔:https://reactjs.org/tutorial/tutorial.htmljson

localhost:1123 yuechunli$ npm install -g create-react-app

3.2 React項目建立

localhost:1123 yuechunli$ create-react-app ipfs-http-demo
localhost:ipfs-http-demo yuechunli$ ls
README.md    package.json    src
node_modules    public        yarn.lock
localhost:ipfs-http-demo yuechunli$

3.3 運行React項目

localhost:ipfs-http-demo yuechunli$ 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.107:3000/

Note that the development build is not optimized.
To create a production build, use yarn build.

3.4 瀏覽項目

瀏覽器瀏覽http://localhost:3000api

效果以下:跨域

3.5 安裝ipfs-api

⚠️:在這裏我就不過多的去介紹React的使用以及開發,若是感興趣的能夠去看這套React的視頻,學完這套視頻你能夠直接進企業找React相關的前端開發工做。瀏覽器

  • 項目結構

  • 安裝ipfs-api

切換到項目根目錄,安裝ipfs-api

$ npm uninstall --save ipfs-api
localhost:ipfs-http-demo yuechunli$ ls
README.md    package.json    src
node_modules    public        yarn.lock
localhost:ipfs-http-demo yuechunli$ pwd
/Users/liyuechun/Desktop/1123/ipfs-http-demo
localhost:ipfs-http-demo yuechunli$ npm uninstall --save ipfs-api

⚠️:ipfs安裝完後,如上圖所示,接下來刷新一下瀏覽器,看看項目是否有問題,正常來說,一切會正常,???,Continue,Continue,Continue......

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"
            style={{width: 200,height: 40,borderWidth:2}}/>
          <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中而且展現出來。

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" style={{
          width: 200,
          height: 40,
          borderWidth: 2
        }}/>
      <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 )配置,依次在終端執行下面的代碼:

localhost:ipfs-http-demo yuechunli$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST", "OPTIONS"]'

localhost:ipfs-http-demo yuechunli$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]'

localhost:ipfs-http-demo yuechunli$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials '["true"]'

localhost:ipfs-http-demo yuechunli$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Headers '["Authorization"]'

localhost:ipfs-http-demo yuechunli$ ipfs config --json API.HTTPHeaders.Access-Control-Expose-Headers '["Location"]'

用正確的端口運行daemon:

localhost:ipfs-http-demo yuechunli$ ipfs config Addresses.API
/ip4/127.0.0.1/tcp/5001
localhost:ipfs-http-demo yuechunli$ ipfs config Addresses.API /ip4/127.0.0.1/tcp/5001
localhost:ipfs-http-demo yuechunli$ ipfs daemon

3.11 再次刷新網頁提交數據並在線查看數據

  • 上傳數據,而且查看返回hash值

  • 在線查看上傳到IPFS的數據

3.12 從IPFS讀取數據

  • ipfs.cat
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" style={{
          width: 200,
          height: 40,
          borderWidth: 2
        }}/>
      <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;

3.13 總結

這篇文章主要講解如何配置React環境,如何建立React項目,如何安裝js-ipfs-api,如何上傳數據,如何設置開發環境,如何下載數據等等內容。經過這篇文章的系統學習,你會掌握js-ipfs-api在項目中的使用流程。

這是【IPFS + 區塊鏈 系列】 入門篇 - IPFS + Ethereum (上篇)-js-ipfs-api,下篇講解如何將IPFS和以太坊智能合約結合進行數據存儲。

4. 下篇文章預告

這是【IPFS + 區塊鏈 系列】 入門篇 - IPFS + Ethereum (上篇)-js-ipfs-api,下篇講解如何將IPFS和以太坊智能合約結合進行數據存儲。

5. 技術交流

  • 區塊鏈技術交流QQ羣:348924182
  • 進微信羣請加微信:liyc1215
  • 「區塊鏈部落」官方公衆號

相關文章
相關標籤/搜索