7-4、5、6 react+ipfs上传文件数据及相关配置(react+区块链实战)
- 7-4 react+ipfs上传文件
- 7-5 react+ipfs 上传数据+ipfs跨域配置
- 7-6 react+ipfs读取ipfs网络数据
7-4 react+ipfs上传文件
引入之前安装的ipfs-api
在电脑后台启动ipfs的服务
ipfs daemon(这个是go-api的不使用)
这里直接使用jsipfs进行后台服务启动
发现版本不兼容,之前还可以启动来,这估计是新安装ipfs-desktop导致的
jsipfs daemon(使用js的版本可以启动)
一个是0.8.0版本的
一个是0.6版本的
这里没有卸载ipfs桌面版,在重启电脑后启动jsipfs daemon就能打开js的ipfs服务了
如果出现了某个模块未安装的情景
关闭start
执行
Npm install
执行npm start后结果应如下
此处是上传文本的,也可以改成上传文件的按钮
文本上传之后会显示哈希值显示在页面
我们可以将文本读取
上方未做值的拼接先不用
显示不是一串字符故下方
使用下方
handleClick(){
console.log(this.state.text)
}
<input value={this.state.text} onChange={(e)=>{
this.setState(
{text:e.target.value}
)
}}/>
上方input将value输入的值保存到state状态中的text中,点击提交时,会调用打印
将状态state中的text打印出来如下
//将input中的内容保存到ipfs上
saveTextToIpfs(text){
//要将其转换成buffer上传
const descBuf = Buffer.from(text,'utf-8')
ipfs.add(descBuf).then(res=>{
console.log(res)
})
}
handleClick(){
this.saveTextToIpfs(this.state.text)
//console.log(this.state.text) //打印保存到状态中的text值
}
值浏览器刷新看到有报错(预料之中的报错,由于跨域导致的)
预料之中的报错,由于跨域导致的
第一个错误跨域导致的
第二个错误是逻辑问题
想向5001端口发送,但是我们现在的本地端口是在3000,需要在ipfs之上进行跨域配置(下节课讲)
本节所有代码
import React from 'react';
import ipfsAPI from 'ipfs-api';
let ipfs = ipfsAPI('localhost','5001',{protocol:'http'}) //本地启动服务默认5001端口
class App extends React.Component{
constructor(propos){
super(propos)
//状态,上传内容,上传后的哈希
this.state = {
text : '', //保存上传的文本
content:'',
hash:''
}
//绑定按钮(否则会this穿透)
this.handleClick = this.handleClick.bind(this)
//this.handleReadClick = this.handleReadClick.bind(this) 若不想绑定可以使用下方的箭头函数,两种方式
}
//将input中的内容保存到ipfs上
saveTextToIpfs(text){
//要将其转换成buffer上传
const descBuf = Buffer.from(text,'utf-8')
ipfs.add(descBuf).then(res=>{
console.log(res)
})
}
handleClick(){
this.saveTextToIpfs(this.state.text)
//console.log(this.state.text) //打印保存到状态中的text值
}
handleReadClick(){
}
//console.log(e.target.value)
//e.target.value就是我们输入的值在input中
render(){
return(
<div className='App'>
<input value={this.state.text} onChange={(e)=>{
this.setState(
{text:e.target.value}
)
}}/>
<button onClick={this.handleClick}>submit to ipfs</button>
<hr/>
<p>
{this.state.hash}
</p>
<button onClick={()=>this.handleReadClick()}>read from ipfs</button>
<p>
{this.state.content}
</p>
</div>
);
}
}
export default App
7-5 react+ipfs 上传数据+ipfs跨域配置
之前提交数据发现会报错
实际上像ipfs接口请求数据并没有配置上
在jsipfs daemon启动后进行配置
如下
Jsipfs config show
可以看到所有api相关的配置,我们是没有header相关的配置的
在ipfs教程官网也可搜到相关配置的
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods ‘[“GET”],[“POST”]’
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin ‘[“*”]’
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials ‘[“true”]’
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Headers ‘[“Authorization”]’
jsipfs config --json API.HTTPHeaders.Access-Control-Expose-Headers ‘[“Location”]’
https://www.cnblogs.com/yinian/p/9836853.html
注意:在window环境下,执行以上命令时可能报错,修改命令为:
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods “[“PUT”, “POST”, “GET”, “OPTIONS”]”
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin “[”*“]”
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials “[“true”]”
jsipfs config --json API.HTTPHeaders.Access-Control-Allow-Headers “[“Authorization”]”
jsipfs config --json API.HTTPHeaders.Access-Control-Expose-Headers “[“Location”]”
在cmd命令行输入上方的命令,不对加入
然后show可以看到如下
jsipfs config show
此时跨域配置成功
在展示config多出了API的数据
此时可以重新启动jsipfs daemon,再执行jsipfs config show依然存在
此时再输入123点击提交发现还是这个错误(因为端口冲突了5001)
找到App.js中
将5001的端口改成5002,本地的桌面版的端口与命令行版有冲突
修改代码只让其显示hash
将此hash值复制出来
QmYkMuFZj7tyHFJRVe7ucqMNYGEiSXrjKdudm2mu7UD7er
来到命令行中
jsipfs cat QmYkMuFZj7tyHFJRVe7ucqMNYGEiSXrjKdudm2mu7UD7er
就将值打印出来了
说明文本已经传递到ipfs上了
获取ipfs官网内容的规则
https://ipfs.io/ipfs/QmYkMuFZj7tyHFJRVe7ucqMNYGEiSXrjKdudm2mu7UD7er
如何访问ipfs的官网
https://blog.csdn.net/weixin_30852451/article/details/96953573
209.94.90.1 ipfs.io
更改hosts文件
注意不关机重启的话要刷新DNS在cmd下
ipconfig /flushdns
此时可以访问链接数据了如下
说明本地的ipfs同步到公网之上了
所有代码如下
import React from 'react';
import ipfsAPI from 'ipfs-api';
let ipfs = ipfsAPI('localhost','5002',{protocol:'http'}) //本地启动服务默认5001端口
class App extends React.Component{
constructor(propos){
super(propos)
//状态,上传内容,上传后的哈希
this.state = {
text : '', //保存上传的文本
content:'',
hash:''
}
//绑定按钮(否则会this穿透)
this.handleClick = this.handleClick.bind(this)
//this.handleReadClick = this.handleReadClick.bind(this) 若不想绑定可以使用下方的箭头函数,两种方式
}
//将input中的内容保存到ipfs上
saveTextToIpfs(text){
//要将其转换成buffer上传
const descBuf = Buffer.from(text,'utf-8')
ipfs.add(descBuf).then(res=>{
console.log(res[0].hash)
})
}
handleClick(){
this.saveTextToIpfs(this.state.text)
//console.log(this.state.text) //打印保存到状态中的text值
}
handleReadClick(){
}
//console.log(e.target.value)
//e.target.value就是我们输入的值在input中
render(){
return(
<div className='App'>
<input value={this.state.text} onChange={(e)=>{
this.setState(
{text:e.target.value}
)
}}/>
<button onClick={this.handleClick}>submit to ipfs</button>
<hr/>
<p>
{this.state.hash}
</p>
<button onClick={()=>this.handleReadClick()}>read from ipfs</button>
<p>
{this.state.content}
</p>
</div>
);
}
}
export default App
7-6 react+ipfs读取ipfs网络数据
在上一章节的基础上
从ipfs读取数据
函数名和命令行基本一致
读取出来的是uint8的数组,完全可以将其转换成string类型的
https://blog.csdn.net/tsyx/article/details/79487645
上方必看
https://www.cnblogs.com/yinian/p/9836740.html
ipfs.cat(this.state.hash).then((stream)=>{
console.log(stream);
var content=stream;
this.setState({content});
});
这里不知为什么点击获取内容时失败报错如下
一直未找到问题,始终报错
尝试重新安装(可能是下载的ipfs-api不够完整)
Npm install
重新启动
Npm start
Jsipfs daemon
还是报错
上传成功后,可以在cmd jsipfs cat hash查看
但就是无法使用代码函数读取ipfs.cat
获取一个哈希值的文件内容失败
视频演示成功如下:
可以将uint8转换成string来展示
完整的效果如下
可以获取内容并显示到了界面
到公网查看数据,本地上传数据后和公网同步也是比较长时间的
命令行是可以读取的
下一章就是react+ipfs+在线教育
将文件上传到ipfs得到哈希值,将哈希值存到以太坊,再通过哈希值从ipfs将文件取出
该问题解决(无法读取ipfs中数据)
直接关闭jsipfs daemon命令行的启动(使用ipfs daemon启动之前的跨域配置此处也配置了)
桌面版自带ipfs的,尽管其使用go-ipfs的接口
但是当其启动后,本身5001的端口,APP.js的端口一改,再进行写入读取就没有错误了
原因很有可能是在windows使用的开启后的API端口和视频中不同后面多了个http
如下
HTTP API listening on /ip4/127.0.0.1/tcp/5002/http
而视频中的没有
解决方案直接启动ipfs daemon(下载的桌面版自带的即可)
再次将代码更改
运行成功后如下
已经得到uint8的字符了,此处需要将其转变为字符串
代码更改
所有的代码如下(确认成功运行):
import React from 'react';
import ipfsAPI from 'ipfs-api';
let ipfs = ipfsAPI('localhost','5001',{protocol:'http'}) //本地启动服务默认5001端口
class App extends React.Component{
constructor(propos){
super(propos)
//状态,上传内容,上传后的哈希
this.state = {
text : '', //保存上传的文本
content:'',
hash:'',
}
//绑定按钮(否则会this穿透)
this.handleClick = this.handleClick.bind(this)
//this.handleReadClick = this.handleReadClick.bind(this) //若不想绑定可以使用下方的箭头函数,两种方式
}
//将input中的内容保存到ipfs上
saveTextToIpfs(text){
//要将其转换成buffer上传
const descBuf = Buffer.from(text,'utf-8')
ipfs.add(descBuf).then(res=>{
//将获取到的hash放到当前状态state的hash中
this.setState({
hash:res[0].hash
})
//console.log(res[0].hash)
})
}
handleClick(){
this.saveTextToIpfs(this.state.text)
//console.log(this.state.text) //打印保存到状态中的text值
}
handleReadClick(){
//console.log(this.state.hash)
//下方代码有误,需测试
ipfs.cat(this.state.hash).then(res=>{
//console.log(res)
let content = new TextDecoder('utf-8').decode(res) //对uint8数组解码为字符串
this.setState({
content
})
})
}
//console.log(e.target.value)
//e.target.value就是我们输入的值在input中
render(){
return(
<div className='App'>
<input value={this.state.text} onChange={(e)=>{
this.setState(
{text:e.target.value}
)
}}/>
<button onClick={this.handleClick}>submit to ipfs</button>
<hr/>
<p>
hash is : {this.state.hash}
</p>
<button onClick={()=>this.handleReadClick()}>read from ipfs</button>
<p>
{this.state.content}
</p>
</div>
);
}
}
export default App