我正在用Express JS开发React应用程序,使用CRA。我想上传一张图片到图像托管服务(如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需要由我的后端服务器处理,这是否意味着图像上传应该从我的后端服务器完成?如果有,是怎么做到的?因为我试图用一个控制器做一个专用的路由,试图做一个简单的请求(没有图片,只是一个POST请求1键:值),但我不能让我的控制器使用fetch。它显然不被认为是一个函数。我确实安装了"node-fetch"。包,正如许多教程中建议的那样,但是导入它似乎很困难:
- 我不能做
const fetch = require("node-fetch")
,这会返回一个错误,指出这种形式的导入是不支持的 - 我不能做
import fetch from "node-fetch"
,这返回另一个错误,因为我的控制器不是模块 - 我可以做
const fetch = import ("node-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。
提前感谢您的帮助
所以我最终自己解决了这个问题。回答我自己的问题,这样其他遇到类似困难的人就能找到出路。
我认为我最大的两个错误是当我可以使用axios时,我试图坚持使用fetch2/坚持自由图像。当我尝试使用axios时,事情变得更顺利了,后来我放弃了freeimage。Host for 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)
我希望这对某些人有用。
如果响应头不包含access-control-allow-origin "origin",浏览器将阻止从其他服务器发送的请求。或"*"。
您可以从节点服务器上传图像。
从React上传图像到Node。然后,将图片上传到freeimage.host"使用Axios, node-fetch等
我个人使用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
}
}
我希望它能帮到你