<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Website Development on KnightLi Blog</title>
        <link>https://knightli.com/es/tags/website-development/</link>
        <description>Recent content in Website Development on KnightLi Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>es</language>
        <lastBuildDate>Fri, 10 Jul 2026 06:24:49 +0800</lastBuildDate><atom:link href="https://knightli.com/es/tags/website-development/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Cómo integrar una API de flujo ComfyUI en un sitio web: frontend, backend, cola y resultados</title>
        <link>https://knightli.com/es/2026/07/10/comfyui-workflow-api-website-integration/</link>
        <pubDate>Fri, 10 Jul 2026 06:24:49 +0800</pubDate>
        
        <guid>https://knightli.com/es/2026/07/10/comfyui-workflow-api-website-integration/</guid>
        <description>&lt;p&gt;Integrar un workflow de ComfyUI en un sitio web no consiste solo en llamar una API. Un flujo usable necesita formulario, API backend, mapeo de parámetros, subida de imágenes, cola, polling de estado, almacenamiento de resultados y errores claros.&lt;/p&gt;
&lt;p&gt;La forma segura es que el backend sea dueño del workflow JSON. El usuario solo modifica parámetros permitidos; el backend los inserta en la plantilla y envía la tarea a ComfyUI.&lt;/p&gt;
&lt;h2 id=&#34;separa-dos-capas-de-api&#34;&gt;Separa dos capas de API
&lt;/h2&gt;&lt;p&gt;Hay dos capas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;La API de tu sitio, llamada por el navegador.&lt;/li&gt;
&lt;li&gt;La API de ComfyUI, llamada por tu backend.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No expongas ComfyUI directamente a internet. Debe ser un servicio interno de render.&lt;/p&gt;
&lt;h2 id=&#34;bucle-mínimo&#34;&gt;Bucle mínimo
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Usuario completa formulario
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; backend crea tarea
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; backend mapea parámetros al workflow
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; backend envía a ComfyUI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; frontend consulta estado
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; backend obtiene el resultado
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; frontend muestra o descarga
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Con esto ya tienes una primera versión.&lt;/p&gt;
&lt;h2 id=&#34;diseño-de-api-backend&#34;&gt;Diseño de API backend
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;POST /api/generate
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GET  /api/tasks/{taskId}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GET  /api/tasks/{taskId}/result
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;POST /api/generate&lt;/code&gt; debe crear la tarea y devolver &lt;code&gt;taskId&lt;/code&gt;. No mantengas esa petición abierta hasta que termine la imagen.&lt;/p&gt;
&lt;h2 id=&#34;mantén-tu-propio-estado&#34;&gt;Mantén tu propio estado
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;queued
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;running
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;succeeded
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;failed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;expired
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Aunque ComfyUI tenga queue e history, tu producto necesita un estado estable para la interfaz.&lt;/p&gt;
&lt;h2 id=&#34;no-dejes-que-usuarios-envíen-workflow-json&#34;&gt;No dejes que usuarios envíen workflow JSON
&lt;/h2&gt;&lt;p&gt;El usuario solo debería controlar campos seguros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prompt;&lt;/li&gt;
&lt;li&gt;negative prompt;&lt;/li&gt;
&lt;li&gt;style;&lt;/li&gt;
&lt;li&gt;size;&lt;/li&gt;
&lt;li&gt;seed;&lt;/li&gt;
&lt;li&gt;imagen subida;&lt;/li&gt;
&lt;li&gt;strength o steps dentro de límites.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aceptar workflow JSON arbitrario puede exponer modelos, nodos, rutas o tareas costosas.&lt;/p&gt;
&lt;h2 id=&#34;mantén-mapeo-de-parámetros&#34;&gt;Mantén mapeo de parámetros
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;form.prompt -&amp;gt; workflow node text
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;form.seed -&amp;gt; sampler seed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;form.width -&amp;gt; latent width
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;form.height -&amp;gt; latent height
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Así puedes cambiar el workflow sin rehacer todo el frontend.&lt;/p&gt;
&lt;h2 id=&#34;subida-de-imágenes&#34;&gt;Subida de imágenes
&lt;/h2&gt;&lt;p&gt;Para image-to-image o referencia:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sube al backend.&lt;/li&gt;
&lt;li&gt;Valida tipo y tamaño.&lt;/li&gt;
&lt;li&gt;Guarda temporalmente.&lt;/li&gt;
&lt;li&gt;Pasa el archivo a ComfyUI.&lt;/li&gt;
&lt;li&gt;Borra al expirar.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No confíes solo en nombre de archivo o MIME del navegador.&lt;/p&gt;
&lt;h2 id=&#34;interacción-del-frontend&#34;&gt;Interacción del frontend
&lt;/h2&gt;&lt;p&gt;Debe mostrar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;validación;&lt;/li&gt;
&lt;li&gt;progreso de subida;&lt;/li&gt;
&lt;li&gt;cola o generación;&lt;/li&gt;
&lt;li&gt;mensaje de espera;&lt;/li&gt;
&lt;li&gt;vista previa;&lt;/li&gt;
&lt;li&gt;reintento;&lt;/li&gt;
&lt;li&gt;error comprensible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Un spinner infinito no basta.&lt;/p&gt;
&lt;h2 id=&#34;pseudocódigo-de-envío&#34;&gt;Pseudocódigo de envío
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;receive request
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;validate user input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;create task record
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;load workflow template
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;patch safe parameters into workflow
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;submit prompt to ComfyUI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;save prompt_id and task status
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;return taskId
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Luego un worker o polling actualiza el estado.&lt;/p&gt;
&lt;h2 id=&#34;dónde-guardar-resultados&#34;&gt;Dónde guardar resultados
&lt;/h2&gt;&lt;h3 id=&#34;opción-1-proxy-desde-backend&#34;&gt;Opción 1: proxy desde backend
&lt;/h3&gt;&lt;p&gt;Sirve para herramientas internas pequeñas. El backend descarga desde ComfyUI y devuelve al navegador.&lt;/p&gt;
&lt;h3 id=&#34;opción-2-almacenamiento-de-objetos&#34;&gt;Opción 2: almacenamiento de objetos
&lt;/h3&gt;&lt;p&gt;Para sitios públicos, sube a S3, R2, OSS u otro storage. Guarda URL y metadatos en la base de datos.&lt;/p&gt;
&lt;h2 id=&#34;por-qué-necesitas-una-cola&#34;&gt;Por qué necesitas una cola
&lt;/h2&gt;&lt;p&gt;La generación es lenta y la GPU es limitada. Sin cola, varios clics pueden saturar el servicio.&lt;/p&gt;
&lt;p&gt;Controla:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;concurrencia;&lt;/li&gt;
&lt;li&gt;límites por usuario;&lt;/li&gt;
&lt;li&gt;reintentos;&lt;/li&gt;
&lt;li&gt;timeout;&lt;/li&gt;
&lt;li&gt;prioridad;&lt;/li&gt;
&lt;li&gt;uso de GPU.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;errores-claros-para-usuarios&#34;&gt;Errores claros para usuarios
&lt;/h2&gt;&lt;p&gt;Convierte fallos internos en mensajes útiles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prompt inválido;&lt;/li&gt;
&lt;li&gt;archivo demasiado grande;&lt;/li&gt;
&lt;li&gt;generación agotó tiempo;&lt;/li&gt;
&lt;li&gt;modelo no disponible;&lt;/li&gt;
&lt;li&gt;cola llena;&lt;/li&gt;
&lt;li&gt;resultado expirado.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Los detalles técnicos deben quedar en logs.&lt;/p&gt;
&lt;h2 id=&#34;protecciones-antes-de-producción&#34;&gt;Protecciones antes de producción
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;autenticación o cuota;&lt;/li&gt;
&lt;li&gt;límites de subida;&lt;/li&gt;
&lt;li&gt;checks de prompt y contenido;&lt;/li&gt;
&lt;li&gt;límites de parámetros;&lt;/li&gt;
&lt;li&gt;control de concurrencia;&lt;/li&gt;
&lt;li&gt;timeout y cancelación;&lt;/li&gt;
&lt;li&gt;expiración de resultados;&lt;/li&gt;
&lt;li&gt;monitoreo de costes;&lt;/li&gt;
&lt;li&gt;allowlist de modelos y nodos;&lt;/li&gt;
&lt;li&gt;protección de APIs internas.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;runninghub-o-comfyui-propio&#34;&gt;RunningHub o ComfyUI propio
&lt;/h2&gt;&lt;p&gt;RunningHub y servicios alojados reducen infraestructura y sirven para validar rápido. ComfyUI propio da control sobre modelos, nodos, coste GPU, datos y workflows personalizados.&lt;/p&gt;
&lt;p&gt;Usa hosting para pruebas rápidas; self-hosting cuando necesites control.&lt;/p&gt;
&lt;h2 id=&#34;orden-recomendado&#34;&gt;Orden recomendado
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;Ejecuta el workflow manualmente.&lt;/li&gt;
&lt;li&gt;Congela una plantilla.&lt;/li&gt;
&lt;li&gt;Expón pocos parámetros seguros.&lt;/li&gt;
&lt;li&gt;Crea API de tareas.&lt;/li&gt;
&lt;li&gt;Añade polling.&lt;/li&gt;
&lt;li&gt;Guarda resultados.&lt;/li&gt;
&lt;li&gt;Añade cola y límites.&lt;/li&gt;
&lt;li&gt;Añade monitoreo y limpieza.&lt;/li&gt;
&lt;li&gt;Agrega más workflows.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;faq&#34;&gt;FAQ
&lt;/h2&gt;&lt;h3 id=&#34;el-frontend-puede-llamar-comfyui-directamente&#34;&gt;¿El frontend puede llamar ComfyUI directamente?
&lt;/h3&gt;&lt;p&gt;No es recomendable en sitios públicos. Usa backend.&lt;/p&gt;
&lt;h3 id=&#34;hace-falta-websocket&#34;&gt;¿Hace falta WebSocket?
&lt;/h3&gt;&lt;p&gt;No al principio. Polling basta; WebSocket puede mejorar progreso después.&lt;/p&gt;
&lt;h3 id=&#34;pueden-usuarios-subir-workflow-json&#34;&gt;¿Pueden usuarios subir workflow JSON?
&lt;/h3&gt;&lt;p&gt;Normalmente no. Mantén workflows en backend.&lt;/p&gt;
&lt;h3 id=&#34;dónde-guardar-resultados-1&#34;&gt;¿Dónde guardar resultados?
&lt;/h3&gt;&lt;p&gt;En producción, object storage suele ser mejor que el disco de ComfyUI.&lt;/p&gt;
&lt;h3 id=&#34;un-sitio-puede-usar-varios-workflows&#34;&gt;¿Un sitio puede usar varios workflows?
&lt;/h3&gt;&lt;p&gt;Sí. Usa IDs de workflow y mapeos separados.&lt;/p&gt;
&lt;h3 id=&#34;video-e-imagen-se-integran-igual&#34;&gt;¿Video e imagen se integran igual?
&lt;/h3&gt;&lt;p&gt;La estructura es parecida, pero video necesita más timeout, almacenamiento, cola y progreso.&lt;/p&gt;
&lt;h2 id=&#34;resumen&#34;&gt;Resumen
&lt;/h2&gt;&lt;p&gt;Trata ComfyUI como motor interno de render. El backend controla workflow, cola, estado, almacenamiento y límites. El frontend solo recoge entradas seguras y muestra progreso y resultados.&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
