I have set up a gcloud bucket with the right permissions and created a service account that has the role storage creator. I have also written a go backend that generates the signed url and passes it to next. The signed url is working as I have tried it with a curl command and it uploaded everything correctly. The problem arises when I try to upload a file from my nextjs application. I have a simple form and a onSubmit handler that gets the file from the form, passes it to formData and uploads the whole thing. For some reason I get the 403 Forbidden error message. I tried looking at some bucket logs but there was nothing. (maybe i didn't set up the logging correctly).I tried to do the same with some vanilla js still didn't work.
Here is my nextjs code.
"use client"
import { getSignedURLs } from "../../upload/upload"
export default function Images(props) {
const submitImages = (e) => {
e.preventDefault()
const form = e.currentTarget
const data = new FormData(form)
const file = data.get("file")
getSignedURLs(1).then((r) => {
console.log(r[0])
let signed = r[0]
console.log(`${file.type}`)
fetch(signed, {
headers: {
"Content-Type": `${file.type}`,
},
method: "PUT",
body: file,
})
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok")
}
return response.json()
})
.then((data) => {
console.log("Response data:", data)
})
.catch((error) => {
console.error("There was a problem with your fetch operation:", error)
})
})
}
return (
<form id="uploadForm" onSubmit={submitImages} encType="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>
)
}
Note that I have tested the getSignedUrl function and I'm sure it returns the correct url. I've also played around with the content type but with no luck. This is now my vanilla js.
document
.getElementById("uploadForm")
.addEventListener("submit", function (event) {
event.preventDefault();
const formData = new FormData();
formData.append("file", this.file.files[0]);
getSignedURLs(1).then((r) => {
let signed = r[0];
fetch(signed, {
method: "PUT",
body: formData,
})
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
})
.then((data) => {
console.log("Response data:", data);
})
.catch((error) => {
console.error(
"There was a problem with your fetch operation:",
error
);
});
});
});
UPDATE:
Trying out a few things I noticed that while using sites like https://restninja.io/ to make a request everything works fine. It doesn't work tho when I specify a content-type, only when I leave it empty. This doesn't solve my problem as i still cannot reproduce the desired behaviour in my js.
Try these to override browser's default headers:
headers: {
"Content-Length": file.size,
"Content-Type": file.type,
},