Mierzę się ostatnio z problemem wczytywania obrazka za pomocą fetch API. Szukałem odpowiedzi na stackoverflow, ale tam piszą jedynie jak tego nie robić. Skonstruowałem działający (tzn niedziałający) przykład. Dostaję w konsoli przeglądarki komunikat "SyntaxError: Unexpected token r in JSON at position 0".
package main
import (
"log"
"net/http"
"html/template"
"fmt"
"io/ioutil"
"mime/multipart"
)
func main() {
http.Handle("/", http.FileServer(http.Dir("./static")))
http.HandleFunc("/upload", UploadFile)
http.HandleFunc("/uploadForm", uploadForm)
log.Println("Running")
http.ListenAndServe(":8080", nil)
}
func uploadForm(w http.ResponseWriter, r *http.Request) {
htmlTemplate := `
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<form action="/asdf" enctype="multipart/form-data" method="post" style="width:100%;" onsubmit="return validateForm(this)">
<textarea name="content" style="width: 100%;"></textarea>
<div class="toolbar">
<input
type="file"
id="fileElem"
name="file"
accept="image/*"
style="display:none"
onchange="onSelectFile();"/>
<label id="fileLabel"></label>
<button id="fileSelect" type="button">Choose File</button>
<input type="submit" value="Submit">
</div>
</form>
<script>
function validateForm(node) {
var content = node.firstElementChild.value;
if (content.length < 1) {
alert("You cannot post empty content!");
return false;
}
return true;
}
const fileSelect = document.getElementById("fileSelect");
const fileElem = document.getElementById("fileElem");
fileSelect.addEventListener(
"click", (e) => {
if (fileElem) {
fileElem.click();
}
}, false)
const input = document.getElementById('fileElem');
const onSelectFile = () => {
document.getElementById("fileLabel").innerHTML = input.files[0].name;
uploadFile(input.files[0]);
}
const uploadFile = (file) => {
fetch('/upload', {
method: 'POST',
headers: {},
body: file // This is your file object
}).then(
response => response.json()
).then(
success => console.log(success)
).catch(
error => console.log(error)
);
};
</script>
</body>
</html>
`
t := template.New("tmpl.html")
t, _ = t.Parse(htmlTemplate)
t.Execute(w, nil)
}
// UploadFile uploads a file to the server
func UploadFile(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
file, handle, err := r.FormFile("file")
if err != nil {
fmt.Fprintf(w, "%v", err)
return
}
defer file.Close()
mimeType := handle.Header.Get("Content-Type")
switch mimeType {
case "image/jpeg":
saveFile(w, file, handle)
case "image/png":
saveFile(w, file, handle)
default:
jsonResponse(w, http.StatusBadRequest, "The format file is not valid.")
}
}
func saveFile(w http.ResponseWriter, file multipart.File, handle *multipart.FileHeader) {
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Fprintf(w, "%v", err)
return
}
err = ioutil.WriteFile("./static/"+handle.Filename, data, 0666)
if err != nil {
fmt.Fprintf(w, "%v", err)
return
}
jsonResponse(w, http.StatusCreated, "File uploaded successfully!.")
}
func jsonResponse(w http.ResponseWriter, code int, message string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
fmt.Fprint(w, message)
}
file, handle, err := r.FormFile("file")
Na stackoverflow piszą aby dodać w fetch requestheaders: { 'Content-Type': undefined, },
co nic nie zmieniar
wSyntaxError: Unexpected token r in JSON at position 0"
, bo komunikat błędu zaczyna się od litery r.append
tak jak tutaj: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#uploading_a_file czy tutaj: https://flaviocopes.com/fix-formdata-multipart-fetch/