complete chapter 4 translation to spanish
This commit is contained in:
168
es/04.5.md
Normal file
168
es/04.5.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# 4.5 Subida de archivos
|
||||
|
||||
Supón que tienes un sitio web como Instagram y quieres que tus usuarios suban sus fotos. ¿Cómo implementarías esa funcionalidad?
|
||||
|
||||
Tienes que agregar la propuedad `enctype` al formulario que vas a usar para subir fotos. Aquí están los tres posibles valores para esta propiedad
|
||||
You have to add property `enctype` to the form that you want to use for uploading photos. There are three possible values for this property:
|
||||
|
||||
```
|
||||
application/x-www-form-urlencoded. Transforma todos los caracteres antes de subirlos (Por defecto).
|
||||
multipart/form-data Sin transformación. Debes usar esta valor cuando vas a subir fotos.
|
||||
text/plain Convierte los espacios en "+" sin transformar los caracteres.
|
||||
```
|
||||
|
||||
Entonces el contenido HTML para subir un archivo debería verse como esto:
|
||||
|
||||
```
|
||||
<html>
|
||||
<head>
|
||||
<title>Upload file</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="http://127.0.0.1:9090/upload" method="post">
|
||||
<input type="file" name="uploadfile" />
|
||||
<input type="hidden" name="token" value="{{.}}"/>
|
||||
<input type="submit" value="Subit" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
|
||||
Necesitamos añadir la funcionalidad al servidor para manejar este formulario.
|
||||
|
||||
```
|
||||
http.HandleFunc("/upload", upload)
|
||||
|
||||
// lógica de subida
|
||||
func upload(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("method:", r.Method)
|
||||
if r.Method == "GET" {
|
||||
crutime := time.Now().Unix()
|
||||
h := md5.New()
|
||||
io.WriteString(h, strconv.FormatInt(crutime, 10))
|
||||
token := fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
t, _ := template.ParseFiles("upload.gtpl")
|
||||
t.Execute(w, token)
|
||||
} else {
|
||||
r.ParseMultipartForm(32 << 20)
|
||||
file, handler, err := r.FormFile("uploadfile")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
fmt.Fprintf(w, "%v", handler.Header)
|
||||
f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
io.Copy(f, file)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Como puedes ver, llamamo a `r.ParseMultipartForm` para subir archivos. La función ParseMultipartForm toma el argumento `maxMemory`. Después de llamar `ParseMultipartForm`, el archivo puede ser guardado en el servidor con tamaño `maxMemory`. Si el tamaño del archivo es mayor que `maxMemory`, el resto del archivo será guardado en un archivo temporal del sistema. Puedes usar `r.FormFile` para obtener el archivo y usar `io.Copy` para guardarlo en tu sistema.
|
||||
|
||||
Puede que no necesites llamar a `r.ParseForm` cuando acceses a otros campos, porque Go llamará a este método si es necesario. También llamar a `ParseMultipartForm` una vez es suficiente, múltiples llamadas no hacen diferencia.
|
||||
|
||||
Usamos tres pasos para subir archivos:
|
||||
|
||||
1. Agregar `enctype="multipart/form-data"` a tu formulario
|
||||
2. Llamar `r.ParseMultipartForm` en el lado del servidor para guardar el archivo en memoria o en un archivo temporal.
|
||||
3. Llamar `r.FormFile` para obtener el archivo y guardarlo en el sistema de ficheros.
|
||||
|
||||
El manejador del archivo es `multipart.FileHeader`. Este usa la siguiente estructura:
|
||||
|
||||
```
|
||||
type FileHeader struct {
|
||||
Filename string
|
||||
Header textproto.MIMEHeader
|
||||
// contains filtered or unexported fields
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
Figure 4.5 Imprimir la información del servidor después de recibir el archivo.
|
||||
|
||||
## Cliente para subir archivos
|
||||
|
||||
Les mostré en el ejemplo anterior como usar un formulario para subir un archivo. Nosotros podemos usar un cliente en Go para emular la subida de archivos.
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func postFile(filename string, targetUrl string) error {
|
||||
bodyBuf := &bytes.Buffer{}
|
||||
bodyWriter := multipart.NewWriter(bodyBuf)
|
||||
|
||||
// este paso es muy importante
|
||||
fileWriter, err := bodyWriter.CreateFormFile("uploadfile", filename)
|
||||
if err != nil {
|
||||
fmt.Println("error writing to buffer")
|
||||
return err
|
||||
}
|
||||
|
||||
// Abrir el archivo para manejarlo
|
||||
fh, err := os.Open(filename)
|
||||
if err != nil {
|
||||
fmt.Println("error opening file")
|
||||
return err
|
||||
}
|
||||
|
||||
//iocopy
|
||||
_, err = io.Copy(fileWriter, fh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contentType := bodyWriter.FormDataContentType()
|
||||
bodyWriter.Close()
|
||||
|
||||
resp, err := http.Post(targetUrl, contentType, bodyBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
resp_body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(resp.Status)
|
||||
fmt.Println(string(resp_body))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ejemplo de uso
|
||||
func main() {
|
||||
target_url := "http://localhost:9090/upload"
|
||||
filename := "./astaxie.pdf"
|
||||
postFile(filename, target_url)
|
||||
}
|
||||
```
|
||||
|
||||
El código de arriba muestra como usar un cliente para subir archivos. El usa `multipart.Write` para escribir archivos en un cache y enviarlos al servidor a través de un método POST.
|
||||
|
||||
Si tienes otros campos que necesitas escribir en el cuerpo del mensaje, como un nombre d eusuario, llama a `multipart.WriteField` cada que lo necesites.
|
||||
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Índice](preface.md)
|
||||
- Sección anterior: [Envíos duplicados](04.4.md)
|
||||
- Siguiente sección: [Resumen](04.6.md)
|
||||
Reference in New Issue
Block a user