I have a html page that has the follow code.
<form action="/image" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="Submit">
</form>
I then have some Go code to get the file on the back end.
func uploaderHandler(w http.ResponseWriter, r *http.Request) {
userInput := r.FormValue("file")
but anytime I try to use userInput from the go script, it returns nothing. Am I passing the variables wrong?
EDIT: I know how to upload things to golang that are text/passwords. I am having trouble uploading images to Go with the code.
EDIT 2: Read the Go guide a found the solution. See below.
First you need to use req.FormFile not FormValue, then you will have to manually save the image to a file.
Something like this:
func HandleUpload(w http.ResponseWriter, req *http.Request) {
in, header, err := req.FormFile("file")
if err != nil {
//handle error
}
defer in.Close()
//you probably want to make sure header.Filename is unique and
// use filepath.Join to put it somewhere else.
out, err := os.OpenFile(header.Filename, os.O_WRONLY, 0644)
if err != nil {
//handle error
}
defer out.Close()
io.Copy(out, in)
//do other stuff
}
Related
I am trying to achieve something similar to the Go Playground's share button.
When a button called share is clicked, the current HTML response is saved into a file. That also includes everything a user can see.
What I can do so far
- I can successfully save an HTML page into a file.
- I can get and save a whole page from a URL using HTTP Get.
Caveats
- I can't save a current webpage I am working on.
This is my code so far for getting remote URLs:
func HTTPGet(url string, timeout time.Duration) (content []byte, err error) {
request, err := http.NewRequest("POST", url, nil)
if err != nil {
return
}
ctx, cancel_func := context.WithTimeout(context.Background(), timeout)
request = request.WithContext(ctx)
response, err := http.DefaultClient.Do(request)
if err != nil {
return
}
defer response.Body.Close()
if response.StatusCode != 200 {
cancel_func()
return nil, fmt.Errorf("INVALID RESPONSE; status: %s", response.Status)
}
return ioutil.ReadAll(response.Body)
}
Hopefully this will not involve messing with the DOM manually.
There is a few ways this can be done, with some cooperation from the client.
If you want to save the current web page as it is displayed to the client (with the current form values, etc.), you have to do that with Javascript on the client side. You can get the document, serialize it in some form and send it to the server to save it.
Alternative is to generate the HTML page on the server side again, but that will not contain data user entered, or any dynamically generated HTML on the client side.
Another way is to use Javascript on the client side to collect page state including form values and data representing any dynamically generated content, send it to the server to save, and reconstruct the page as needed.
Normally I use JSON API and SPA for when I make web apps, but I am trying to learn how to use the more simple method server-side templating and default form behavior with Go.
I am doing something very similar to what is seen here. The only difference is that I changed the action to "/" in the form for simplicity and handle the GET and POST from the same Handler (filtering by method type).
Server-Side Template
<form action="/" method="post" >
...
<div class="form-group">
<label for="myname">Dev Name</label>
<input type="text" class="form-control" id="myname" name="myname" value="{{.MyDname}}">
</div>
<button type="submit" class="btn btn-primary">Update</button>
</form>
Server side
func MainPage(w http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method) //get request method
if r.Method == "GET" {
t, err := template.New("RTL Page").Parse(page)
if err != nil {
log.Fatal(err)
}
err = t.Execute(w, State)
if err != nil {
log.Fatal(err)
}
}
if r.Method == http.MethodPost {
r.ParseForm()
...
}
}
The initial web page renders fine, the data gets sent correctly in a POST, I answer the POST with a just a 200 but then my webpage goes blank.
How do I tell the browser to keep or rerender the original page? Do I need to send an HTML response to the POST? Something other than a 200?
What you are asking is the basic operation of HTTP. The client sends a request, and the server responds to the request. If the client is a browser, the browser displays the response.
For GET request, browser sends the GET request to the server, the server responds with an HTML page, and browser displays it.
For POST request, browser sends the POST request along with the values submitted in the form, and the server should respond with an HTML page, so the browser can dispay it. The response displayed will be a POST response, so if you reload that page, it will try to resubmit the form.
#Volker pointed out what needed to change. The POST needed to be answered by the HTML I wanted displayed, so the real simple way to fix this is:
func MainPage(w http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method) //get request method
if r.Method == http.MethodPost {
r.ParseForm()
...
}
if r.Method == "GET" || r.Method == "POST" {
t, err := template.New("RTL Page").Parse(page)
if err != nil {
log.Fatal(err)
}
err = t.Execute(w, State)
if err != nil {
log.Fatal(err)
}
}
}
I am currently working on a Go web server utilizing the builtin templates.
The current issue I am having is that when I run the web server, it is serving the correct files but it does not load any media on the site.(Such as pictures and fonts) When I run the .html file as it is all media is loaded so I know it has something to do with my back end. Here is my code :
var templates = template.Must(template.ParseGlob("static/*.html"))
...
func index(w http.ResponseWriter, r *http.Request) {
currentTime := time.Now().Local()
toSend := payload{
Date: currentTime.Format("01-02-2006"),
Status: "Active",
}
t, err := template.ParseFiles("static/index.html")
if err != nil {
log.Fatalf("Error parsing template: %v", err)
}
t.Execute(w, toSend)
}
...
And here is my file path:
app
|-main.go
|-static(contains static files)
|-media(contains all media)
|-index.html
This serves the templates perfectly fine with all the required data yet without any media. All help is appreciated thank you!
Answered by #Adrian in the comments, I simply wasn't loading the media assets via the go server for the html to use.
http.Handle("/media/",http.StripPrefix("/media/",http.FileServer(http.Dir("static/media"))))
Was all I needed
I have some html files in folder /html (for example main.html,page1.html, page2.html,etc ). And I serve it, using next Go code
r := mux.NewRouter()
r.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir(htmlDir))))
So if I open address http://127.0.0.1/page1.html, then page1.html will be shown( it is what I need).
But I also want to bind address http://127.0.0.1/ to main.html. How can I do it?
I can rename main.html to index.html, but I think it is not true way.
You could additionally add a HandlerFunc to handle that:
r := mux.NewRouter()
r.HandleFunc("/", homeHandler)
r.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir(htmlDir))))
In the homeHandler you serve the file you want to serve:
func homeHandler(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, fmt.Sprintf("./%s/index.htm", htmlDir))
}
There might be other options...
Sorry im beginner and i read golang.docs but didnt understand well.
i`ve : index.html:
<html>
<head>
</head>
<body>
<form action type="checkbox" name="test" value="A" {{.checked}}>
<input type="submit" value="save">
</body>
</html>
in main.go
if user click save button then check checkbox redirect that page and show checkbox checked
You could send variables in map. For example:
package main
import (
"bytes"
"fmt"
"text/template"
)
func main() {
t, _ := template.New("hi").Parse("Hi {{.name}}")
var doc bytes.Buffer
t.Execute(&doc, map[string]string{"name": "Peter"})
fmt.Println(doc.String()) //Hi Peter
}
The . is defined in go code.
Please provide the snippet of your go code where the template is executed, something like the following codes:
t, _ := template.ParseFiles(tmpl + ".html")
t.Execute(w, data) // the data must feature the field "checked"
Or
templates.ExecuteTemplate(w, tmpl+".html", data) // the data must feature the field "checked"
You can pass any type(interface{}) to a functions that execute a template as "data". Usually it is a Struct or a Map[string]string.
How to set the checked
Probably the "checked" is setted in the main.go at handler according to the posted form.
Read the docs and explain it better. Please