No puedo hacer que la incrustación funcione

Hola, estoy intentando incrustar comentarios de Discourse en mi sitio web siguiendo la guía de incrustación, pero he dado con un muro :frowning:

Síntomas

Lo he probado en Firefox y Chrome. En ambos casos, carga el iframe de Discourse con el mensaje “Cargando discusión…”, pero se queda colgado allí, con errores de JavaScript recurrentes en la consola de desarrollador.

En Firefox, obtengo un error sobre X-Frame-Options:

Se encontró un encabezado X-Frame-Options inválido al cargar “https://discourse.29th.local/embed/comments?embed_url=https%3A%2F%2Fpersonnel.29th.local%2F%23enlistments%2F11927”: “ALLOWALL” no es una directiva válida.

Seguido de un error DOMException en embed-application.js:7:

Uncaught DOMException: Se especificó una cadena inválida o ilegal

Estos dos errores se repiten cada 30 segundos aproximadamente. No hay solicitudes fallidas en la pestaña de red.

En Chrome, no obtengo el error de X-Frame-Options. Después de unos segundos, obtengo un error sobre que el origen de destino no coincide con el origen de la ventana receptora:

Error al ejecutar 'postMessage' en 'DOMWindow': El origen de destino proporcionado ('https://discourse.29th.local') no coincide con el origen de la ventana receptora ('https://personnel.29th.local').

He visto muchos temas en meta sobre este error y he probado todos los pasos de solución de problemas, sin éxito.

Mi configuración

Seguí la guía de configuración de Discourse para Mac con una pequeña excepción: en lugar de instalar postgres, redis y mailcatcher globalmente en mi portátil, los tengo ejecutándose en contenedores Docker, con los puertos expuestos públicamente. Discourse no tiene idea de que se están ejecutando en contenedores Docker en lugar de en hardware físico. Rails/Discourse está instalado globalmente y no se está ejecutando en un contenedor Docker.

Por separado, mi aplicación web personalizada se está ejecutando en una pila de Docker Compose. Parte de esa pila incluye un servidor nginx que enruta personnel.29th.local al contenedor upstream correspondiente y discourse.29th.local a host.docker.internal:3000 (ese es el nombre de host mágico que los contenedores Docker pueden usar para alcanzar el localhost del host).

(Como menciono más abajo, eliminé la capa de nginx de la ecuación y terminé con el mismo error)

Una posible trampa aquí es que mi aplicación web es una aplicación de una sola página (SPA) en JavaScript. La página donde se incrustan los comentarios de Discourse es https://personnel.29th.local/#enlistments/1234 y no hay renderizado del lado del servidor. Si eso fuera un problema, esperaría un error con el rastreador, momento en el cual me conformaría con que Discourse simplemente enlazara a mi aplicación en lugar de rastrearla. Pero los errores que muestra no parecen relacionarse con fallos de rastreo.

Solución de problemas

He establecido el host incrustable en Admin > Personalizar > Incrustación en personnel.29th.local. Al principio, el código de ejemplo de incrustación mostraba http://localhost:3000/ para discourseUrl, así que inicié rails console y ejecuté:

SiteSetting.force_hostname = "discourse.29th.local"
SiteSetting.port = 443

Y activé “forzar https” en el panel de administración. Esto corrigió la URL en el código de ejemplo de incrustación.

También agregué https://personnel.29th.local como dominio CORS en la sección cors origins de la configuración.

Ahora estoy iniciando Discourse con el siguiente comando:

DISCOURSE_DEV_HOSTS=discourse.29th.local,host.docker.internal DISCOURSE_ENABLE_CORS=true bundle exec rails server

También intenté desactivar la Política de Seguridad de Contenido (CSP) en el panel de configuración.

He revisado https://discourse.29th.local/logs/ pero no he visto errores ni nada sobre Sidekiq.

En cuanto a Sidekiq, tengo un mensaje en el panel de administración sobre actualizaciones:

No se ha realizado una comprobación de actualizaciones. Asegúrese de que Sidekiq se esté ejecutando.

Así que ejecuté Sidekiq.redis { |r| puts r.flushall } en la consola de Rails y obtuve OK, reinicié el servidor de Rails y no hubo cambios en el mensaje ni en el problema general. He revisado la caché de Redis y no veo nada relacionado con esta página.

También intenté simplificar las cosas eliminando la capa de nginx de la ecuación: restableciendo SiteSetting.force_hostname y SiteSetting.port a nil, desactivando el forzado de https, accediendo a mi aplicación web y a Discourse a través de localhost, y agregando mi aplicación web a los hosts incrustables y nombres de host CORS de Discourse (http://localhost:8080), pero obtuve el mismo error, solo que con diferentes hosts:

Error al ejecutar 'postMessage' en 'DOMWindow': El origen de destino proporcionado ('http://localhost:3000') no coincide con el origen de la ventana receptora ('http://localhost:8080').

Estoy ejecutando la versión 2.6.0.beta6 ( 60bc38e6a8 ), que obtuve clonando la rama master según la guía de configuración de Discourse para Mac hace un par de semanas y ejecutando git pull origin master hoy.

También he eliminado el directorio tmp y reiniciado el servidor.

También he salido a caminar, gritado en una almohada y llorado debajo de mi escritorio.

Espero que esto cubra todas las bases. ¡Espero que alguien pueda ayudar!

Lamento mucho escuchar que estás teniendo tantas dificultades para configurarlo.

Discourse no es lo suficientemente inteligente como para rastrear una SPA, así que esto me parece lo más sospechoso. ¿Podrías intentar reproducirlo con un sitio que contenga contenido estático?

Es imposible para nosotros dar soporte a cada instalación personalizada, por lo que te recomiendo que intentes simplificar aún más tu pila hasta que funcione, y luego agregues componentes desde ahí.

3 Me gusta

¡Gracias por tu respuesta! No te preocupes, sé que valdrá la pena.

He simplificado las cosas para usar un sitio renderizado en el servidor (Rails) y eliminar por completo la capa de nginx. Tengo mi aplicación ejecutándose en el puerto 3001 y Discourse en el puerto 3000.

Mi código de inserción se renderiza así:

<script type="text/javascript">
      DiscourseEmbed = { discourseUrl: 'http://localhost:3000/',
                         discourseEmbedUrl: 'http://localhost:3001/enlistments/1' };
    
      (function() {
        var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
        d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
      })();
</script>

Añadí localhost:3001 a los hosts insertables en Administración > Personalizar > Inserción y http://localhost:3001 a los nombres de host en Administración > Configuración > CORS.

El error es el mismo, pero con los nombres de host actualizados:

Error al ejecutar 'postMessage' en 'DOMWindow': El origen de destino proporcionado ('http://localhost:3000') no coincide con el origen de la ventana receptora ('http://localhost:3001').

La pila es tan simple como puede ser ahora :thinking: Supongo que eso significa que es algún tipo de problema de configuración. ¿Alguna idea?

Algunos hallazgos adicionales de depuración:

Creé manualmente un tema y reemplacé discourseEmbedUrl: 'http://localhost:3001/enlistments/<%= @enlistment.id %>' por topicId: 14 en mi fragmento de JavaScript, y se cargaron los comentarios. Esto sugiere que no es un problema de CORS o X-Frame-, sino (a) algo relacionado con el raspado (scraping) y (b) posiblemente un problema en la forma en que se manejan los errores durante la incrustación.

Para investigar el problema de raspado, visité una página nueva a la que no había intentado acceder antes (por lo tanto, no debería haberse intentado realizar ningún raspado en ella). Observé la consola de Rails de mi aplicación y cargué la página. Vi /enlistments/6 en el registro una vez. Esperé hasta que se mostrara el mensaje de error en la consola de JavaScript; para ese momento, Discourse debería haber intentado realizar el raspado, pero la consola de Rails de mi aplicación no mostró ningún otro intento de acceso en los registros.

No hubo errores en el endpoint /logs de Discourse, ni ninguno que pudiera identificar en el registro de Rails de Discourse.

Pensé que tal vez Discourse no podía acceder a mi sitio web, así que inicié sesión en la consola de Rails de mi aplicación de Discourse y ejecuté:

± |master U:3 ?:2 ✗| → rails c
Loading development environment (Rails 6.0.3.3)
[1] pry(main)> require "net/http"
=> false
[2] pry(main)> url = URI.parse("http://localhost:3001/enlistments/6")
=> #<URI::HTTP http://localhost:3001/enlistments/6>
[3] pry(main)> req = Net::HTTP.new(url.host, url.port)
=> #<Net::HTTP localhost:3001 open=false>
[4] pry(main)> res = req.request_head(url.path)
4=> #<Net::HTTPOK 200 OK readbody=true>
[5] pry(main)>

Mientras hacía esto, vi el registro de acceso en el servidor de Rails de mi aplicación. Esto confirmó que Discourse puede alcanzar mi aplicación.

Ahora pienso que debe ser un problema con Sidekiq o la programación de tareas. :man_shrugging: No estoy seguro de cómo depurar eso, aunque. Nunca he usado Sidekiq antes.

Revisé nuevamente los datos de Redis (usando TablePlus, una interfaz gráfica de base de datos que funciona con Redis) y veo aproximadamente 3 filas con una key con valores como default:logster-env-96404aef1da0c422fc32e3bb82d85fbc y un value con valores como:

[
  {
    "hostname": "myhostname",
    "process_id": 7188,
    "application_version": "60bc38e6a8914a10341a32ff9909e69faa65ffef",
    "params": {
      "embed_url": "http: //localhost:3001/enlistments/11927"
    },
    "HTTP_HOST": "localhost:3000",
    "REQUEST_URI": "/embed/comments?embed_url=http%3A%2F%2Flocalhost%3A3001%2Fenlistments%2F11927",
    "REQUEST_METHOD": "GET",
    "HTTP_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.60 Safari/537.36",
    "HTTP_ACCEPT": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "HTTP_REFERER": "http://localhost:3000/embed/comments?embed_url=http%3A%2F%2Flocalhost%3A3001%2Fenlistments%2F11927",
    "time": 1606253787041
  }
]

El type es LIST y el ttl es -1. Supongo que eso significa que el trabajo se está iniciando.

He explorado /sidekiq, pero no veo ninguna mención de este trabajo ni ningún tipo de cola llamada RetrieveTopic :frowning:

Definitivamente estoy acotando el problema, pero agradecería una mano si se te ocurre algo.

Hola @eviltrout, ¿tienes alguna idea para seguir con la solución de problemas, ahora que he simplificado la configuración a lo básico?

Casi con seguridad se trata de un problema de configuración. Quizás tu Discourse en localhost:3000 crea que tiene un nombre de host diferente. Puedes verificarlo en una consola usando:

Discourse.base_url

Otra cosa que debes revisar son los registros de sidekiq en /sidekiq.

@eviltrout He añadido algunas líneas de depuración a la librería TopicRetriever y confirmé que invalid_url? es false (lo que sugiere que es válida). Discourse.base_url está efectivamente configurado en http://localhost:3000. Creo que el trabajo RetrieveTopic está fallando silenciosamente en algún lugar y estoy tratando de rastrear dónde. No hay registros de errores en /logs y /sidekiq no tiene ninguna referencia a la recuperación de temas ni registros de ningún tipo.

Lo siento, por el momento no tengo más ideas. Sé que el código funciona actualmente en producción, así que debe tratarse de un problema ambiental, de un plugin o de configuración.

1 me gusta

Hola, gracias por la investigación. Creo que tengo exactamente el mismo problema (el incrustado funciona para un tema existente pero falla al crear un tema). Esto funciona en mi entorno de producción, pero no en mi máquina de desarrollo.

Mi configuración es una pila de Docker, y me aseguré de que todo fuera visible tanto para Discourse como para Sidekiq. En este punto, empiezo a pensar que cuando Discourse intenta analizar una URL (también falla cuando onebox intenta obtener una vista previa de un enlace en una publicación), de alguna manera depende de un servicio externo que no puede ver las instancias locales… ¿Sería eso posible?

@wilson29thid, ¿has encontrado algo de tu parte desde entonces?

Me encontré con el mismo problema en mi máquina de producción, no en mi máquina de desarrollo. Algo me hace pensar que no importa exactamente cuál estés usando.

1 me gusta

No, me temo que nunca pude resolver esto y acabé usando la API de Discourse para crear un tema manualmente :pensive_face:

1 me gusta

Yo también podría hacerlo. Lo bueno es que puedes controlar la cantidad de hilos que se crean antes de que la gente empiece a comentar tus artículos…