Enviar archivo de JavaScript a Golang

Subir archivo de JavaScript a Go (Golang)

En este post de programación cliente-servidor vamos a ver cómo enviar un archivo desde JavaScript del lado del cliente a Golang (Go) del lado del servidor.

Específicamente hablando veremos cómo enviar un archivo usando fetch y FormData a través de AJAX hacia un servidor de Go.

Lo que te enseñaré servirá para enviar fotos, archivos binarios o incluso una foto tomada con la cámara web con las debidos ajustes.

Va a ser un ejemplo realmente simple pero que luego podrás modificar para, por ejemplo, usarlo en React, Angular, JavaScript puro o Vue.

Lado del cliente

Para este ejemplo te enseñaré a enviar el archivo y además un valor adicional de tipo cadena, ya que en otros tutoriales los lectores siempre me preguntan cómo enviar datos adicionales además del archivo.

El código queda así:

En la línea 1 obtenemos los archivos seleccionados en el input, aunque obviamente para este ejemplo solo enviamos uno.

Creamos el FormData en la línea 6 y además de agregarle el archivo (en la clave archivo) le agregamos un dato de tipo cadena (en la clave nombre).

Hacemos la petición usando fetch en la línea 12 y esperamos la respuesta. Si algo sale mal (que por ejemplo el servidor de Go rechace la petición porque la misma es muy grande) entonces se maneja en el catch.

Recuerda que debes modificar la URL del servidor dependiendo del puerto y ruta donde tu servidor de Golang esté escuchando.

Limitando tamaño de archivos

Pasemos a programar en Go. Aquí puedes usar cualquier framework o router, por ejemplo gorilla/mux, ya que al final accederemos a la petición de tipo *http.Request.

Cuando recibimos archivos en Golang debemos poner un límite de tamaño, ya que si alguien envía algo muy grande puede hacer que el servidor se “cuelgue”. Comenzamos limitando el tamaño de la petición:

Y luego la leemos igualmente indicando el límite.

No te confundas, lo que te mostré anteriormente fue para rechazar la petición en caso de que supere el límite, y lo que viene a continuación es para cargar en la RAM solo los bytes permitidos y el sobrante colocarlo en el disco duro.

Esto es importante, ya que por ejemplo si tú quisieras poner un límite de 1GB puedes hacerlo, pero al momento de invocar a ParseMultipartForm podrías pasar un límite de, por ejemplo, 5MB.

De ese modo podrías limitar peticiones a 1GB pero al parsearlas solo cargar 5MB en la RAM y el resto en el disco duro, ahorrando RAM. Yo uso el mismo valor en el ejemplo, pero no lo olvides.

Leyendo archivo y formulario recibido desde JavaScript

Ahora vamos a acceder al archivo que enviamos con fetch desde JavaScript, usando Go.

En este caso accedemos a r.MultipartForm.File pasándole la clave que queremos, esa misma clave que usamos al usar FormData en el cliente (archivo).

Por otro lado, para acceder a los valores que no son archivos (recuerda que enviamos una variable llamada nombre) podemos usar r.Form.Get pasando la clave que usamos en FormData igualmente.

Y ya tenemos abierto el archivo, ahora debemos leerlo y guardarlo en otro lugar, cambiando además su nombre por seguridad.

Guardando archivo recibido en Go

Ya tenemos el archivo que enviaron desde JS, ya sea en la RAM o en el almacenamiento temporal. Ahora hay que copiarlo.

Yo recomiendo renombrarlo a algo aleatorio, conservando su extensión. Recuerda que para acceder al nombre con el que el archivo fue subido podemos acceder a encabezadoPrimerArchivo.Filename.

En la línea 2 creamos el archivo en donde vamos a escribir al que recibimos en el formulario, luego copiamos en la línea 7 y finalmente en la línea 11 escribimos “Subido correctamente” en la respuesta.

Una nota sobre CORS

Si tú no sirves el HTML en el mismo host que Go, debes habilitar CORS y permitir el host desde donde haces las peticiones del cliente.

En el ejemplo ya he incluido las 2 cosas: cómo servir el HTML desde Go y cómo habilitar CORS. Puedes modificar todo de acuerdo a lo que necesites.

Poniendo todo junto

Entonces mi servidor de Go para recibir archivos y guardarlos queda como se ve a continuación, ya con todas las funciones:

Y junto a mi servidor tengo una carpeta llamada public en donde está el archivo enviar.html cuyo contenido es el siguiente:

Luego en la carpeta hacemos un go mod tidy o instalamos las dependencias manualmente y finalmente compilamos con go build, lo que nos dará un ejecutable llamado subir-archivo-go.

Al abrir el archivo nos indica que está escuchando en el puerto 8080, entonces visitamos http://localhost:8080/public/enviar.html, subimos un archivo y vemos que se ha alojado correctamente en el directorio “subidas“:

Enviar archivo de JavaScript a Golang
Enviar archivo de JavaScript a Golang

Por otro lado, si queremos enviar un archivo más grande que el límite nos aparecerá lo siguiente en el log del servidor y en el cliente.

Límite de peso de archivos al subir de JS a Go
Límite de peso de archivos al subir de JS a Go

Ahora que veo el log recuerdo que estábamos enviando una cadena además del archivo. En mi caso solo lo estoy imprimiendo para ejemplificar que sí estamos recibiendo correctamente el valor en el servidor.

Conclusión

El código fuente completo lo dejo en GitHub para que puedas explorarlo.

Cuando empecé a programar en el lado del servidor siempre usé PHP (y lo sigo usando) y al cambiar a Go me di cuenta de que tienes que hacer más cosas y no todo es automático, por ejemplo, en PHP usamos move_uploaded_file, configuramos el ini y todo queda perfecto, mientras que en Go debes personalizar todo escribiendo el código.

Incluso así, me gusta más Go, siento que tengo más control.

Para terminar te dejo con más tutoriales de Go en mi blog.

Encantado de ayudarte


Estoy disponible para trabajar en tu proyecto, modificar el programa del post o realizar tu tarea pendiente, no dudes en ponerte en contacto conmigo.

No te pierdas ninguno de mis posts

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario