目前正在制作一个用于发布聊天信息的基本DApp,类似于Twitter,只是构建在智能合约上。我正在使用hardhat并在localhost上运行我的应用程序。当创建个人资料时,我希望用户能够上传个人资料图片,但目前每当我尝试这样做时,我会收到以下错误:
POST https://ipfs.infura.io:5001/api/v0/add?stream-channels=true&progress=false 401 (Unauthorized)
伴随错误消息:
Error uploading file: HTTPError: project id required
at Object.errorHandler [as handleError] (core.js?edc8:103:1)
at async Client.fetch (http.js?8f3e:149:1)
at async addAll (add-all.js?93f2:36:1)
at async last (index.js?7e49:13:1)
at async Object.add (add.js?6672:22:1)
控制台显示此函数中发生错误:
const uploadToInfura = async (file) => {
try {
const added = await client.add({ content: file });
const url = `https://ipfs.infura.io/ipfs/${added.path}`;
setFileUrl(url);
} catch (error) {
console.log('Error uploading file: ', error);
}
};
型
我将附上下面这个页面的整个代码,如果你可以,请让我知道我需要修复,以便让这个错误停止发生。任何其他提示,我可以改善一般也将不胜感激:)
import { useState, useEffect, useContext, useCallback, useMemo } from 'react'
import { useRouter } from 'next/router';
import { useDropzone } from 'react-dropzone';
import Image from 'next/image';
import { useTheme } from 'next-themes';
import { ethers } from "ethers";
import Web3Modal from 'web3modal';
import { Input, Button, Banner, SearchBar, PostCard, PostCardNFT, SmallInput } from '../components';
import images from '../assets';
import DecentratwitterAbi from './contractsData/decentratwitter.json';
import DecentratwitterAddress from './contractsData/decentratwitter-address.json';
import { Home } from './index'
import { create as ipfsHttpClient } from 'ipfs-http-client';
const client = ipfsHttpClient('https://ipfs.infura.io:5001/api/v0');
const Profile = () => {
const [profile, setProfile] = useState('');
const [posts, setPosts] = useState('');
const [nfts, setNfts] = useState('');
const [fileUrl, setFileUrl] = useState(null);
const [isloading, setIsLoading] = useState(true);
const { theme } = useTheme();
const [files] = useState([]);
const [formInput, updateFormInput] = useState({ username: '' });
const router = useRouter();
const uploadToInfura = async (file) => {
try {
const added = await client.add({ content: file });
const url = `https://ipfs.infura.io/ipfs/${added.path}`;
setFileUrl(url);
} catch (error) {
console.log('Error uploading file: ', error);
}
};
const createProfile = async () => {
const web3Modal = new Web3Modal();
const connection = await web3Modal.connect();
const provider = new ethers.providers.Web3Provider(connection);
const signer = provider.getSigner();
const contract = new ethers.Contract(
DecentratwitterAddress.address,
DecentratwitterAbi.abi,
signer
);
const { username } = formInput;
if (!username || !fileUrl) return;
/* first, upload to IPFS */
const data = JSON.stringify({ username, avatar: fileUrl });
try {
const added = await client.add(data);
const url = `https://ipfs.infura.io/ipfs/${added.path}`;
/* after file is uploaded to IPFS, pass the URL to save it on Polygon */
await contract.mint(url);
fetchMyNFTs();
} catch (error) {
console.log('Error uploading file: ', error);
}
};
const fetchProfile = async (nfts) => {
const web3Modal = new Web3Modal();
const connection = await web3Modal.connect();
const provider = new ethers.providers.Web3Provider(connection);
const signer = provider.getSigner();
const contract = new ethers.Contract(
DecentratwitterAddress.address,
DecentratwitterAbi.abi,
signer
);
const address = await contract.signer.getAddress();
const id = await contract.profiles(address);
const profile = nfts.find((i) => i.id.toString() === id.toString());
setProfile(profile);
setIsLoading(false);
};
const loadPosts = async () => {
const web3Modal = new Web3Modal();
const connection = await web3Modal.connect();
const provider = new ethers.providers.Web3Provider(connection);
const signer = provider.getSigner();
const contract = new ethers.Contract(
DecentratwitterAddress.address,
DecentratwitterAbi.abi,
signer
);
// Get user's address
let address = await contract.signer.getAddress()
setAddress(address)
// Check if user owns an nft
// and if they do set profile to true
const balance = await contract.balanceOf(address)
setHasProfile(() => balance > 0)
// Get all posts
let results = await contract.getAllPosts()
// Fetch metadata of each post and add that to post object.
let posts = await Promise.all(results.map(async i => {
// use hash to fetch the post's metadata stored on ipfs
let response = await fetch(`https://ipfs.infura.io/ipfs/${i.hash}`)
const metadataPost = await response.json()
// get authors nft profile
const nftId = await contract.profiles(i.author)
// get uri url of nft profile
const uri = await contract.tokenURI(nftId)
// fetch nft profile metadata
response = await fetch(uri)
const metadataProfile = await response.json()
// define author object
const author = {
address: i.author,
username: metadataProfile.username,
avatar: metadataProfile.avatar
}
// define post object
let post = {
id: i.id,
content: metadataPost.post,
tipAmount: i.tipAmount,
author
}
return post
}))
posts = posts.sort((a, b) => b.tipAmount - a.tipAmount)
// Sort posts from most tipped to least tipped.
setPosts(posts)
setLoading(false)
};
const fetchMyNFTs = async () => {
const web3Modal = new Web3Modal();
const connection = await web3Modal.connect();
const provider = new ethers.providers.Web3Provider(connection);
const signer = provider.getSigner();
const contract = new ethers.Contract(
DecentratwitterAddress.address,
DecentratwitterAbi.abi,
signer
);
const results = await contract.getMyNfts();
let nfts = await Promise.all(results.map(async i => {
const uri = await contract.tokenURI(i);
const response = await fetch(uri);
const metadata = await response.json();
return ({
id: i,
username: metadata.username,
avatar: metadata.avatar
});
}));
setNfts(nfts);
fetchProfile(nfts);
};
const tip = async (post) => {
const web3Modal = new Web3Modal();
const connection = await web3Modal.connect();
const provider = new ethers.providers.Web3Provider(connection);
const signer = provider.getSigner();
const contract = new ethers.Contract(
DecentratwitterAddress.address,
DecentratwitterAbi.abi,
signer
);
// tip post owner
await (await contract.tipPostOwner(post.id, { value: ethers.utils.parseEther(tipAmount) })).wait()
fetchMyNFTs()
}
useEffect(() => {
fetchMyNFTs()
.then((nfts) => {
setNfts(nfts);
setIsLoading(false);
});
}, []);
const onDrop = useCallback(async (acceptedFile) => {
await uploadToInfura(acceptedFile[0]);
}, []);
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
onDrop,
accept: 'image/*',
maxSize: 5000000,
});
const fileStyle = useMemo(
() => (
`dark:bg-nft-black-1 bg-white border dark:border-white border-nft-gray-2 flex flex-col items-center p-5 rounded-sm border-dashed
${isDragActive ? ' border-file-active ' : ''}
${isDragAccept ? ' border-file-accept ' : ''}
${isDragReject ? ' border-file-reject ' : ''}`),
[isDragActive, isDragReject, isDragAccept],
);
return (
<div className="w-full flex justify-start items-center flex-col min-h-screen">
<div className="w-full flexCenter flex-col">
<Banner
name={
profile ? (
<div>{profile.username}</div>
) : (
"No profile, please create one"
)
}
childStyles="text-center mb-4"
parentStyles="h-80 justify-center"
/>
<div className="flexCenter flex-col -mt-20 z-0">
<div className="flexCenter w-40 h-40 sm:w-36 sm:h-36 p-1 bg-nft-black-2 rounded-full">
{profile ? (
<Image src={profile.avatar} className="rounded-full object-cover" objectFit="cover" width="200%" height="200%" alt='avatar' />
) : (
"No Profile"
)
}
</div>
<p className="font-poppins dark:text-white text-nft-black-1 font-semibold text-2xl mt-6"></p>
</div>
</div>
{profile ? (
<div>
{nfts ? (
nfts.map((nft, key) => {
<div key={key} >
<PostCardNFT
image={<Image src={nft.author.avatar} layout="fixed" width='60' height='40' alt='post' className='rounded-[6px]' />}
content={nft.content}
tipAmount={ethers.utils.formatEther(post.tipAmount)}
address={shortenAddress(post.author.address)}
tipInput={
<div className='pb-2'>
<SmallInput
inputType='number'
title='Tip'
placeholder='ETH'
handleClick={(e) => setTipAmount(e.target.value)}
/>
</div>
}
button={
<Button
btnName="Tip"
btnType="primary"
classStyles="rounded-xl"
handleClick={() => tip(post)}
/>
}
/>
</div>
})
) : (
<div className="text-2xl font-bold pt-20">
No Posts, Create One ...
</div>
)}
</div>
) : (
<div className="w-full px-20">
<Input
inputType="input"
title="Username"
placeholder="Input Username"
handleClick={(e) => updateFormInput({ ...formInput, username: e.target.value })}
/>
<div className="mt-16">
<p className="font-poppins dark:text-white text-nft-black-1 font-semibold text-xl">Profile Avatar</p>
<div className="mt-4">
<div {...getRootProps()} className={fileStyle}>
<>
{fileUrl ? (
<div>
<Image
src={fileUrl}
className="object-cover"
objectFit="cover"
width="200%"
height="200%"
alt="Asset_file" />
</div>
) : (
<div>
<input {...getInputProps()} /><div className="flexCenter flex-col text-center">
<p className="font-poppins dark:text-white text-nft-black-1 font-semibold text-xl">JPG, PNG, GIF, SVG, WEBM, MP3, MP4. Max 100mb.</p>
<div className="my-12 w-full flex justify-center">
<Image
src={images.upload}
width={100}
height={100}
objectFit="contain"
alt="file upload"
className={theme === 'light' ? 'filter invert' : undefined}
/>
</div>
<p className="font-poppins dark:text-white text-nft-black-1 font-semibold text-sm">Drag and Drop File</p>
<p className="font-poppins dark:text-white text-nft-black-1 font-semibold text-sm mt-2">Or browse media on your device</p>
</div>
</div>
)}
</>
</div>
</div>
</div>
<div className="mt-7 w-full flex justify-end">
<Button
btnName="Mint Profile"
btnType="primary"
classStyles="rounded-xl"
handleClick={createProfile} />
</div>
</div>
)}
</div>
);
};
export default Profile;
4条答案
按热度按时间hc2pp10m1#
您缺少授权标头,该标头告诉Infura您是谁,以及您有权访问API。
以下是这些文档的片段:
您只需将一个选项对象和凭据添加到
如上所示。
图片来源:https://docs.infura.io/infura/networks/ipfs/how-to/make-requests#ipfs-http-client
cu6pst1q2#
2022年8月这周我也遇到了这个问题。
授权证书是最近的要求。Infura在其网站上发表了2020-2021年的文章,其中没有提到任何授权证书。他们最近还发表了一篇文章和一段视频,其中确实要求通过API端点进行身份验证才能访问IPFS。下面是公共API的弃用链接,相关信息接近文章末尾。
https://blog.infura.io/post/introducing-ipfs-dedicated-gateways
将auth令牌存储在.env中通常被认为是最佳实践,这样在提交到公共git repo时就不会泄露它们。
不幸的是,如果你在线部署你的应用程序,这仍然不足以保护你的令牌。一旦你到达那里,有很多在线资源可以解决这个问题。
0g0grzrc3#
步骤1:通过输入卡详细信息创建IPFS Infura项目
步骤2:启用专用网关给予任何子域名.
步骤3:
npm install --save buffer
步骤4:在项目中添加以下代码
步骤5:使用类似的专用网关来查看您上传的图像
https://(your gateway name).infura-ipfs.io/ipfs/${result.path}
https://github.com/dappuniversity/nft_marketplace/issues/5#issuecomment-1219131315q7solyqu4#
我浪费了一整天来解决这个问题,以不同的方式更新代码,最后我创建了新的应用程序在infura和测试代码与新的项目ID和秘密,它是为我工作:
脚本代码:
弯曲:
curl -X POST -F文件=@test.png -u“KKKKKKKKEY:SSSSSECRET”“https://ipfs.infura.io:5001/api/v0/add“--不安全-A“ curl ”
它似乎不工作与旧的细节!
谢谢