Impossible d'obtenir l'intégration fonctionnelle

Bonjour, j’essaie d’intégrer des commentaires Discourse sur mon site web, en suivant le guide d’intégration, mais je suis bloqué :frowning:

Symptômes

J’ai testé avec Firefox et Chrome. Dans les deux cas, l’iframe Discourse affiche « Chargement de la discussion… » mais reste bloquée, avec des erreurs JavaScript récurrentes dans la console de développement.

Sous Firefox, j’obtiens une erreur concernant l’en-tête X-Frame-Options :

Invalid X-Frame-Options header was found when loading “https://discourse.29th.local/embed/comments?embed_url=https%3A%2F%2Fpersonnel.29th.local%2F%23enlistments%2F11927”: “ALLOWALL” is not a valid directive.

Suivie d’une erreur DOMException dans embed-application.js:7 :

Uncaught DOMException: An invalid or illegal string was specified

Ces deux erreurs se répètent toutes les 30 secondes environ. Aucune requête échouée n’apparaît dans l’onglet Réseau.

Sous Chrome, je n’obtiens pas l’erreur X-Frame-Options. Après quelques secondes, j’obtiens une erreur indiquant que l’origine cible ne correspond pas à l’origine de la fenêtre destinataire :

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://discourse.29th.local') does not match the recipient window's origin ('https://personnel.29th.local').

J’ai vu de nombreux sujets sur Meta concernant cette erreur et j’ai essayé toutes les étapes de dépannage, sans succès.

Ma configuration

J’ai suivi le guide d’installation de Discourse sur Mac avec une légère exception : au lieu d’installer postgres, redis et mailcatcher globalement sur mon ordinateur portable, je les exécute dans des conteneurs Docker avec les ports exposés publiquement. Discourse ignore qu’ils tournent dans des conteneurs Docker plutôt que directement sur le matériel. Rails/Discourse est installé globalement et ne s’exécute pas dans un conteneur Docker.

Tout à fait séparément, mon application web personnalisée s’exécute dans une stack Docker Compose. Cette stack comprend un serveur nginx qui route personnel.29th.local vers le conteneur amont approprié, et discourse.29th.local vers host.docker.internal:3000 (c’est le nom d’hôte magique que les conteneurs Docker peuvent utiliser pour atteindre le localhost de l’hôte).

(Comme je le mentionne ci-dessous, j’ai retiré la couche nginx de l’équation et obtenu la même erreur)

Un problème potentiel ici est que mon application web est une application monopage (SPA) JavaScript. La page où les commentaires Discourse sont intégrés est https://personnel.29th.local/#enlistments/1234 et il n’y a pas de rendu côté serveur. Si cela posait problème, je m’attendrais à une erreur avec le crawler, auquel cas je me contenterais que Discourse se contente de lier vers mon application plutôt que de la crawler. Mais les erreurs affichées ne semblent pas liées à des échecs de crawl.

Dépannage

J’ai défini l’hôte intégrable dans Admin > Personnaliser > Intégration sur personnel.29th.local. Au début, le code d’intégration d’exemple affichait http://localhost:3000/ pour discourseUrl, alors j’ai lancé rails console et exécuté :

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

J’ai ensuite activé « forcer https » dans le tableau de bord administrateur. Cela a corrigé l’URL dans le code d’intégration d’exemple.

J’ai également ajouté https://personnel.29th.local en tant que domaine CORS dans la section cors origins des paramètres.

Je lance désormais Discourse avec la commande suivante :

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

J’ai également essayé de désactiver la politique de sécurité du contenu (CSP) dans le tableau de bord des paramètres.

J’ai consulté https://discourse.29th.local/logs/ mais je n’ai vu aucune erreur, ni rien concernant Sidekiq.

Concernant Sidekiq, j’ai un message sur le tableau de bord administrateur concernant les mises à jour :

A check for updates has not been performed. Ensure sidekiq is running.

J’ai donc exécuté Sidekiq.redis { |r| puts r.flushall } dans la console Rails et obtenu OK, redémarré le serveur Rails, mais le message et le problème global n’ont pas changé. J’ai exploré le cache Redis et je n’ai rien trouvé concernant cette page.

J’ai également tenté de simplifier les choses en retirant la couche nginx de l’équation : en rétablissant SiteSetting.force_hostname et SiteSetting.port sur nil, en désactivant le forçage de https, en accédant à mon application web et à Discourse via localhost, et en ajoutant mon application web aux hôtes intégrables et aux noms d’hôtes CORS de Discourse (http://localhost:8080), mais j’ai obtenu la même erreur, avec simplement des hôtes différents :

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://localhost:3000') does not match the recipient window's origin ('http://localhost:8080').

J’exécute la version 2.6.0.beta6 ( 60bc38e6a8 ), obtenue en clonant la branche master conformément au guide d’installation de Discourse sur Mac il y a quelques semaines, et en exécutant git pull origin master aujourd’hui.

J’ai également supprimé le répertoire tmp et redémarré le serveur.

J’ai aussi fait une promenade, crié dans un oreiller et pleuré sous mon bureau.

J’espère que cela couvre tous les aspects. J’espère que quelqu’un pourra m’aider !

Je suis désolé d’apprendre que vous rencontrez tant de difficultés pour la configuration.

Discourse n’est pas assez intelligent pour explorer une SPA, donc cela me semble être l’hypothèse la plus probable. Pouvez-vous essayer de reproduire le problème avec un site contenant du contenu statique ?

Il nous est impossible de prendre en charge chaque installation personnalisée, je vous recommande donc de simplifier davantage votre pile technologique jusqu’à ce que cela fonctionne, puis d’ajouter des éléments à partir de là.

3 « J'aime »

Merci pour votre réponse, et pas de souci, je sais que cela en vaut la peine !

J’ai simplifié les choses en utilisant un site rendu côté serveur (Rails) et en supprimant entièrement la couche Nginx. J’ai mon application qui tourne sur le port 3001 et Discourse sur le port 3000.

Mon code d’intégration est rendu comme ceci :

<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>

J’ai ajouté localhost:3001 aux hôtes intégrables dans Administration > Personnalisation > Intégration et http://localhost:3001 aux noms d’hôte dans Administration > Paramètres > CORS.

L’erreur est la même, mais avec les noms d’hôte mis à jour :

Échec de l'exécution de 'postMessage' sur 'DOMWindow' : l'origine cible fournie ('http://localhost:3000') ne correspond pas à l'origine de la fenêtre destinataire ('http://localhost:3001').

La pile est aussi simple que possible maintenant :thinking: Je suppose que cela signifie qu’il s’agit d’un problème de configuration d’une manière ou d’une autre ? Des idées ?

Quelques résultats supplémentaires du débogage :

J’ai créé manuellement un sujet et remplacé discourseEmbedUrl: 'http://localhost:3001/enlistments/<%= @enlistment.id %>' par topicId: 14 dans mon extrait JavaScript, et les commentaires se sont chargés. Cela suggère qu’il ne s’agit pas d’un problème de CORS ou de X-Frame, mais (a) de quelque chose lié au scraping, et (b) possiblement d’un problème de gestion des erreurs lors de l’intégration.

Pour investiguer le problème de scraping, j’ai visité une nouvelle page que je n’avais jamais tenté d’accéder auparavant (et donc aucun scraping n’aurait dû être tenté sur celle-ci). J’ai observé la console Rails de mon application et chargé la page. J’ai vu /enlistments/6 apparaître une fois dans les journaux. J’ai attendu que le message d’erreur soit affiché dans la console JavaScript, moment où Discourse aurait dû tenter de faire le scraping, mais la console Rails de mon application n’a montré aucune autre tentative d’accès.

Il n’y avait aucune erreur dans le point de terminaison /logs de Discourse, ni aucune que je puisse distinguer dans le journal Rails de Discourse.

Je pensais peut-être que Discourse ne pouvait pas accéder à mon site web, alors je me suis connecté à la console Rails de mon application Discourse et j’ai exécuté :

± |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)>

Pendant ce temps, j’ai vu le journal d’accès dans le serveur Rails de mon application. Cela a confirmé que Discourse peut atteindre mon application.

Maintenant, je pense que cela doit être un problème avec Sidekiq ou la planification des tâches ? :man_shrugging: Je ne sais pas trop comment déboguer cela, cependant. Je n’ai jamais utilisé Sidekiq auparavant.

J’ai jeté un autre coup d’œil aux données Redis (en utilisant TablePlus, une interface graphique de base de données compatible Redis), et je vois environ 3 lignes avec une key ayant des valeurs comme default:logster-env-96404aef1da0c422fc32e3bb82d85fbc et une value avec des valeurs comme

[
  {
    "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
  }
]

le type est LIST et le ttl est -1. Je suppose que cela signifie que la tâche est en cours d’initialisation ?

J’ai fouillé dans /sidekiq mais je ne vois aucune mention de cette tâche ni d’une file d’attente appelée RetrieveTopic :frowning:

Je réduis certainement le champ des possibilités, mais je pourrais avoir besoin d’un coup de main si quelque chose vous vient à l’esprit !

Salut @eviltrout, as-tu des idées pour d’autres dépannages, maintenant que j’ai simplifié la configuration aux bases ?

C’est presque certainement un problème de configuration. Peut-être que votre Discourse sur localhost:3000 pense avoir un nom d’hôte différent. Vous pouvez vérifier dans une console en utilisant :

Discourse.base_url

Une autre chose à vérifier sont les journaux de sidekiq à /sidekiq.

@eviltrout J’ai ajouté quelques lignes de débogage dans la bibliothèque TopicRetriever et confirmé que invalid_url? vaut false (ce qui suggère que l’URL est valide). Discourse.base_url est bien défini sur http://localhost:3000. Je pense que le job RetrieveTopic échoue silencieusement quelque part, et j’essaie de localiser l’origine du problème. Il n’y a aucune trace d’erreur dans /logs, et /sidekiq ne contient aucune référence à la récupération de sujets ni aucun journal d’activité.

Désolé, je n’ai plus d’idées pour le moment. Je sais que le code fonctionne actuellement en production, donc il doit s’agir d’un problème d’environnement, d’un plugin ou d’une configuration.

1 « J'aime »

Bonjour, merci pour votre enquête. Je pense avoir exactement le même problème (l’intégration fonctionne pour un sujet existant mais échoue lors de la création d’un sujet). Cela fonctionne dans mon environnement de production mais pas sur ma machine de développement.

Mon environnement est une pile Docker, et j’ai veillé à ce que tout soit accessible depuis Discourse et Sidekiq. À ce stade, je commence à penser que lorsque Discourse tente d’analyser une URL (cela échoue également lorsqu’une onebox essaie de récupérer un aperçu d’un lien dans un message), cela dépend d’un service externe qui ne parvient pas à voir les instances locales… Est-ce possible ?

@wilson29thid, avez-vous trouvé quelque chose de votre côté depuis ?

J’ai rencontré le même problème sur ma machine de production, pas sur celle de développement. Quelque chose me fait penser que cela n’a pas vraiment d’importance laquelle vous utilisez.

1 « J'aime »

Non, j’ai peur de ne jamais avoir résolu ce problème et d’avoir fini par utiliser l’API de Discourse pour créer un sujet manuellement :pensive_face:

1 « J'aime »

Je pourrais bien le faire aussi. Le bon point, c’est que tu peux contrôler le nombre de threads créés avant que les gens ne commencent à commenter tes articles…