我正在使用 Express JS 和 CRA 开发 React 应用程序。我想尽可能“简单”地将图片上传到图像托管服务(例如 imgur、imageshack 或 freeimage.host),并获取其 URL,以便我可以在我的应用程序上显示它。但我在 CORS 方面遇到了很多麻烦。
郑重声明,我对 CORS 以及它如何防止向不同域发出请求有一个基本的了解。我也看到很多人对 CORS 有疑问,其要点似乎是 CORS 必须由后端服务器处理,而不是前端。我不太明白。
郑重声明,这本质上是我的测试组件(React),我正在其中尝试上传图片。
import React, { useState, useContext } from 'react'
import { Form } from 'react-bootstrap'
export default function testUpload() {
const [file, setFile] = useState(undefined);
const handleEditForm = inputEvent => {
const { files } = inputEvent.target;
console.log(files[0]);
setFile(files[0]);
}
const apiSendPic = async () => {
const formData = new FormData()
formData.append('file', file)
formData.append("firstName", "Yamakyu")
await fetch(
'https://freeimage.host/api/1/upload?key=6d207e02198a847aa98d0a2a901485a5',
{
method: 'POST',
body: formData,
}
)
.then((response) => response.json())
.then((result) => {
console.log('Success:', result);
})
.catch((error) => {
console.error('Error:', error);
});
}
return (
<div>
<button onClick={apiSendPic}>Upload</button>
<Form>
<Form.Group controlId="fileName">
<Form.Label className='VerticalLabel'>Photo ou image :</Form.Label> <br />
<Form.Control
className='LargeInput'
type="file"
name='image'
onChange={handleEditForm}
size="lg"
/>
</Form.Group>
</Form>
</div>
)
}
这是我的 server.js (我删除了与问题无关的所有内容,例如所有其他路线等)
const path = require("path");
const express = require("express");
const app = express();
const db = require("./models");
const cors = require("cors");
const PORT = process.env.PORT || 8081;
const corsOptions = {
origin: "*",
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus: 200,
};
app.use(cors(corsOptions));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "./build_front")));
const RouteTest = require("./Routes/RouteTest");
app.use("/api/test", RouteTest);
db.sequelize.sync();
app.use("/api/reset", userController.isLoggedIn, (req, res) => {
db.sequelize
.sync({ force: true })
.then(() => {
console.log("DROP and re-sync db.");
})
.catch((err) => console.log(`Error while dropping/syncing db : ${err}`));
return res.status(200).json({
message: "Database droped",
needLogout: false,
});
});
app.get("*", (_, res) => res.sendFile("index.html", { root: "build" }));
app.listen(PORT, () => {
console.log(`Listening to port ${PORT}.`);
});
我不太明白的一件事是,如果 CORS 需要由我的后端服务器处理,这是否意味着图像上传应该从我的后端服务器完成?如果是这样,怎么办?因为我尝试使用控制器创建一条专用路由,以尝试发出一个简单的请求(没有图片,只是一个带有 1 个键:值的 POST 请求),但我无法让我的控制器使用 fetch。它显然不被识别为函数。我确实按照许多教程中的建议安装了“node-fetch”包,但导入它似乎很困难:
const fetch = require("node-fetch")
,这会返回一个错误,指出不支持这种形式的导入import fetch from "node-fetch"
,这会返回另一个错误,因为我的控制器不是模块const fetch = import ("node-fetch")
,但是 fetch 不会被识别为函数这是我的控制器的一部分(路由工作正常,我可以很好地调用这个 api,api 本身不起作用)。
const db = require("../models");
const fetch = import("node-fetch");
exports.upload = async (req, res) => {
try {
await fetch("https://freeimage.host/api/1/upload?key=6d207e02198a847aa98d0a2a901485a5", {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify({
name: "yamakyu",
}),
})
.then((res) => res.json())
.then((data) => {
console.log("API response ↓");
console.log(data.message);
});
} catch (error) {
console.log("↓ ------- ERROR ↓");
console.log(error);
return res.status(500).json({
error,
});
}
};
我有点不知所措。我觉得这应该不复杂,但我感觉很困难。 我只想上传图片并获取其 URL。
提前感谢您的帮助
所以我最终自己解决了这个问题。回答我自己的问题,以便其他遇到类似斗争的人可以找到出路。
我认为我的第二个最大的错误是 1/ 当我可以使用 axios 时尝试坚持使用 fetch 2/ 当存在其他图像托管 API 时,坚持使用 freeimage.host。
当我尝试使用 axios 时,事情变得更加顺利,然后过了一会儿,当我放弃 freeimage.host 转而使用 imgbb.com 时。
这就是我所做的。首先,使用 npm i axios 和 npm i form-data 安装 axios 和 form-data。从那里,我可以使用我习惯的
require('axios')
语法导入它。您还想请求 API 密钥。对于 imgbb.com,您需要创建一个帐户并在此处请求密钥 https://api.imgbb.com/
这是使其工作的重要代码片段
const fs = require("fs");
const axios = require("axios");
const formData = require("form-data");
const uploadAxios = () => {
try {
console.log("ping !");
const myFile = fs.readFileSync(
`YOUR_FILE_LOCATION_ON_YOUR_COMPUTER`, { encoding: "base64" }
);
const myForm = new formData();
myForm.append("image", myFile);
await axios
.post(
`https://api.imgbb.com/1/upload?key=YOUR_KEY_YOU_GOT_ON_THE_API_PAGE`,
myForm,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
)
.then((response) => {
console.log("API response ↓");
console.log(response);
})
.catch((err) => {
console.log("API error ↓");
console.log(err);
if (err.response.data.error) {
console.log(err.response.data.error);
//When trouble shooting, simple informations about the error can be found in err.response.data.error so it's good to display it
}
});
} catch (error) {
console.log(error);
}
这是我能做到的最简单的。可能还有其他方法,具有更好的格式或更精确的选项,但这对我有用。在控制台中显示 API 响应将使您看到图像 URL 可以在 response.data.data.url.
中找到当然,所有这些都是在我的 Express 服务器中的一个控制器中完成的(因为最初的问题是 CORS)
我希望这对某些人有用。
我遇到了同样的错误,然后我使用了其他 api 方法,它是免费的、相似的且易于使用
const handleImageChange = async (e) => { const 文件 = e.target.files[0];
if (file && file.type.startsWith("image/")) {
const formData = new FormData();
formData.append("image", file); // Append the image file
try {
const response = await axios.post(
"https://api.imgbb.com/1/upload?key=you_key
”, 表单数据, { 标题:{ '内容类型':'多部分/表单数据', }, } );
console.log(response.data); // Log the response data
} catch (error) {
console.error("Error uploading image:", error);
}
} else {
console.error("Selected file is not an image.");
}
};
如果响应标头不包含 access-control-allow-origin“origin”或“*”,浏览器会阻止在不同服务器上发送的请求。
您可以从节点服务器上传图片。
将图像从 React 上传到 Node。然后,使用 Axios、node-fetch 等将图像上传到“freeimage.host”
上传文件我个人使用express-fileupload。
// conf/express.js
const fileUpload = require("express-fileupload");
const cors = require("cors");
//...
app.use(fileUpload());
app.use(cors());
app.options("*", cors());
//...
module.exports = app;
我就这样使用它:
const fileExists = require("file-exists");
const path = require("path");
const app = require("./conf/express");
//...
// get an image
app.get("/images/:id", async (req, res) => {
return res.sendFile(path.resolve("./images/" + req.params.id));
});
// post an image
app.post("/images", async (req, res) => {
if (!req.files) {
// return error
}
if (req.files.file) {
let file = req.files.file;
if (!["image/jpeg", "image/png", "image/heic", "application/octet-stream"].includes(file.mimetype)) {
// return error (or not it depend if you only want an image)
}
let newFileName = Utils.generateId(30); //random name, or not
file.mv(path.resolve("images/" + newFileName + ".png"), function (err) {
if (err) {
console.error(err);
}
// process.env.MYSELF_URL is http://localhost:3000 for example
let imagePath = process.env.MYSELF_URL + "/images/" + newFileName + ".png";
// return success with image path that correspond to
});
} else {
// return error
}
}
希望能帮到你