Einbettung funktioniert nicht

Hallo, ich versuche, Discourse-Kommentare auf meiner Website einzubetten, und folge dabei dem Einbettungsguide, aber ich bin an eine Wand gelaufen :frowning:

Symptome

Ich habe es in Firefox und Chrome versucht. In beiden Fällen wird das Discourse-iFrame „Discussion wird geladen…“ geladen, bleibt aber hängen, wobei im Entwickler-Tool wiederholt JavaScript-Fehler auftreten.

In Firefox erhalte ich einen Fehler bezüglich X-Frame-Options:

Bei dem Laden von „https://discourse.29th.local/embed/comments?embed_url=https%3A%2F%2Fpersonnel.29th.local%2F%23enlistments%2F11927“ wurde ein ungültiger X-Frame-Options-Header gefunden: „ALLOWALL“ ist keine gültige Direktive.

Danach folgt ein DOMException-Fehler in embed-application.js:7:

Uncaught DOMException: Es wurde eine ungültige oder illegale Zeichenfolge angegeben

Diese beiden Fehler wiederholen sich alle ca. 30 Sekunden. Im Network-Tab gibt es keine fehlgeschlagenen Anfragen.

In Chrome bekomme ich keinen X-Frame-Options-Fehler. Nach einigen Sekunden erhalte ich einen Fehler, dass die angegebene Ziel-Quelle nicht mit der Quelle des Empfänger-Fensters übereinstimmt:

Ausführung von 'postMessage' auf 'DOMWindow' fehlgeschlagen: Die angegebene Ziel-Quelle ('https://discourse.29th.local') stimmt nicht mit der Quelle des Empfänger-Fensters ('https://personnel.29th.local') überein.

Ich habe bereits viele Themen auf Meta zu diesem Fehler gesehen und alle Fehlerbehebungsschritte ausprobiert, leider ohne Erfolg.

Meine Einrichtung

Ich habe mich an den Einrichtungsleitfaden für Discourse auf dem Mac gehalten, mit einer kleinen Ausnahme: Anstatt PostgreSQL, Redis und Mailcatcher global auf meinem Laptop zu installieren, lasse ich sie in Docker-Containern laufen, wobei die Ports öffentlich freigegeben sind. Discourse hat keine Ahnung, dass sie in Docker-Containern und nicht auf der physischen Hardware laufen. Rails/Discourse ist global installiert und läuft nicht in einem Docker-Container.

Völlig separat läuft meine benutzerdefinierte Webanwendung in einem Docker-Compose-Stack. Ein Teil dieses Stacks ist ein Nginx-Server, der personnel.29th.local an den entsprechenden Upstream-Container und discourse.29th.local an host.docker.internal:3000 weiterleitet (das ist der magische Hostname, den Docker-Container verwenden können, um auf das localhost des Hosts zuzugreifen).

(Wie unten erwähnt, habe ich die Nginx-Schicht aus der Gleichung entfernt und landete beim selben Fehler)

Ein möglicher Stolperstein hier ist, dass meine Webanwendung eine JavaScript-Single-Page-App ist. Die Seite, auf der Discourse-Kommentare eingebettet werden, lautet https://personnel.29th.local/#enlistments/1234, und es gibt kein serverseitiges Rendering. Wenn das ein Problem wäre, würde ich einen Fehler beim Crawler erwarten, woraufhin ich mich damit zufriedengeben würde, dass Discourse einfach einen Link zu meiner App setzt, anstatt sie zu crawlen. Aber die angezeigten Fehler scheinen sich nicht auf Crawling-Fehler zu beziehen.

Fehlerbehebung

Ich habe die einbettbare Host-Adresse unter Admin > Anpassen > Einbettung auf personnel.29th.local gesetzt. Zunächst zeigte der Beispiel-Einbettungscode http://localhost:3000/ für die discourseUrl an, also habe ich rails console gestartet und folgendes ausgeführt:

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

Und im Admin-Dashboard „HTTPS erzwingen“ aktiviert. Damit wurde die URL im Beispiel-Einbettungscode korrigiert.

Ich habe zudem https://personnel.29th.local als CORS-Domain im Abschnitt cors origins der Einstellungen hinzugefügt.

Jetzt starte ich Discourse mit folgendem Befehl:

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

Ich habe auch versucht, die Content Security Policy im Einstellungs-Dashboard zu deaktivieren.

Ich habe unter https://discourse.29th.local/logs/ nachgeschaut, aber keine Fehler und nichts bezüglich Sidekiq gefunden.

Was Sidekiq angeht, habe ich eine Meldung im Admin-Dashboard zu Updates:

Ein Check auf Updates wurde nicht durchgeführt. Stellen Sie sicher, dass Sidekiq läuft.

Also habe ich Sidekiq.redis { |r| puts r.flushall } in der Rails-Konsole ausgeführt und OK erhalten, den Rails-Server neu gestartet, aber weder die Meldung noch das Gesamtproblem haben sich geändert. Ich habe im Redis-Cache herumgesucht und nichts zu dieser Seite gefunden.

Ich habe zudem versucht, die Sache zu vereinfachen, indem ich die Nginx-Schicht aus der Gleichung genommen habe: SiteSetting.force_hostname und SiteSetting.port wieder auf nil gesetzt, „HTTPS erzwingen“ deaktiviert, meine Webanwendung und Discourse über localhost aufgerufen und meine Webanwendung zu den einbettbaren Hosts und CORS-Hostnamen von Discourse hinzugefügt (http://localhost:8080). Doch ich bekam denselben Fehler, nur mit anderen Hosts:

Ausführung von 'postMessage' auf 'DOMWindow' fehlgeschlagen: Die angegebene Ziel-Quelle ('http://localhost:3000') stimmt nicht mit der Quelle des Empfänger-Fensters ('http://localhost:8080') überein.

Ich verwende die Version 2.6.0.beta6 ( 60bc38e6a8 ), die ich vor ein paar Wochen durch Klonen des master-Branches gemäß dem Discourse-for-Mac-Einrichtungsleitfaden erhalten und heute mit git pull origin master aktualisiert habe.

Ich habe zudem das tmp-Verzeichnis gelöscht und den Server neu gestartet.

Ich bin auch spazieren gegangen, habe in ein Kissen geschrien und unter meinem Schreibtisch geweint.

Hoffentlich habe ich hiermit alle Möglichkeiten abgedeckt. Ich hoffe, jemand kann mir helfen!

Es tut mir leid zu hören, dass du bei der Einrichtung so große Schwierigkeiten hast.

Discourse ist nicht in der Lage, eine SPA zu crawlen, daher klingt das für mich am verdächtigsten. Könntest du versuchen, das Problem mit einer Seite mit statischem Inhalt zu reproduzieren?

Es ist unmöglich für uns, jede individuelle Installation zu unterstützen. Daher empfehle ich dir, deinen Stack weiter zu vereinfachen, bis es funktioniert, und dann schrittweise weitere Komponenten hinzuzufügen.

3 „Gefällt mir“

Danke für deine Antwort, und keine Sorge, ich weiß, dass es sich lohnen wird!

Ich habe die Sache vereinfacht, indem ich eine serverseitig gerenderte (Rails-)Site verwende und die Nginx-Ebene komplett weglasse. Meine App läuft auf Port 3001 und Discourse auf Port 3000.

Mein Embed-Code wird so gerendert:

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

Ich habe localhost:3001 zu den einbettbaren Hosts unter Admin > Anpassen > Einbettung und http://localhost:3001 zu den Hostnamen unter Admin > Einstellungen > CORS hinzugefügt.

Der Fehler ist derselbe, nur mit den aktualisierten Hostnamen:

Ausführung von 'postMessage' auf 'DOMWindow' fehlgeschlagen: Der angegebene Zielursprung ('http://localhost:3000') stimmt nicht mit dem Ursprung des empfangenden Fensters ('http://localhost:3001') überein.

Der Stack ist jetzt so einfach wie möglich :thinking: Ich gehe davon aus, dass es sich um ein Konfigurationsproblem handelt? Hast du Ideen?

Weitere Debugging-Ergebnisse:

Ich habe manuell ein Topic erstellt und in meinem JavaScript-Snippet discourseEmbedUrl: 'http://localhost:3001/enlistments/<%= @enlistment.id %>' durch topicId: 14 ersetzt, und die Kommentare wurden geladen. Das deutet darauf hin, dass es sich nicht um ein CORS- oder X-Frame-Problem handelt, sondern (a) um etwas im Zusammenhang mit dem Scraping und (b) möglicherweise um ein Problem bei der Fehlerbehandlung während des Embeddings.

Um das Scraping-Problem zu untersuchen, habe ich eine neue Seite besucht, auf die ich zuvor noch keinen Zugriff versucht hatte (und auf die daher noch kein Scraping versucht wurde). Ich habe die Rails-Konsole meiner App beobachtet und die Seite geladen. Ich sah /enlistments/6 einmal im Log. Ich wartete, bis die Fehlermeldung in der JavaScript-Konsole ausgegeben wurde; zu diesem Zeitpunkt hätte Discourse das Scraping versucht, aber die Rails-Konsole meiner App zeigte keine weiteren Zugriffsversuche.

Es gab keine Fehler im /logs-Endpunkt von Discourse, und auch in der Rails-Log von Discourse konnte ich nichts erkennen.

Ich dachte, vielleicht könnte Discourse nicht auf meine Website zugreifen, also habe ich mich in der Rails-Konsole meiner Discourse-App angemeldet und Folgendes ausgeführt:

± |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)
=> #<Net::HTTPOK 200 OK readbody=true>
[5] pry(main)>

Währenddessen sah ich im Zugriffslog meines App-Rails-Servers den Eintrag. Das bestätigte, dass Discourse meine App erreichen kann.

Jetzt denke ich, es muss ein Problem mit Sidekiq oder der Job-Planung sein? :man_shrugging: Ich bin mir jedoch nicht sicher, wie man das debuggt. Ich habe Sidekiq noch nie verwendet.

Ich habe mir die Redis-Daten erneut angesehen (mit TablePlus, einer Datenbank-GUI, die mit Redis funktioniert), und ich sehe etwa drei Zeilen mit einem key wie default:logster-env-96404aef1da0c422fc32e3bb82d85fbc und einem value wie:

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

Der type ist LIST und ttl ist -1. Ich vermute, das bedeutet, dass der Job gestartet wird?

Ich habe mich im /sidekiq-Bereich umgeschaut, aber ich sehe weder eine Erwähnung dieses Jobs noch eine Warteschlange namens RetrieveTopic :frowning:

Ich komme definitiv näher an die Ursache heran, könnte aber Hilfe gebrauchen, falls Ihnen etwas einfällt!

Hey @eviltrout, hast du jetzt, da ich das Setup auf das Nötigste reduziert habe, weitere Ideen zur Fehlerbehebung?

Es handelt sich fast sicher um ein Konfigurationsproblem. Möglicherweise geht Ihr Discourse unter localhost:3000 von einem anderen Hostnamen aus. Sie können dies in einer Konsole überprüfen mit:

Discourse.base_url

Eine weitere Sache, die Sie prüfen sollten, sind die Sidekiq-Logs unter /sidekiq.

@eviltrout Ich habe einige Debugging-Zeilen in die TopicRetriever-Bibliothek eingefügt und bestätigt, dass invalid_url? false ist (was darauf hindeutet, dass die URL gültig ist). Discourse.base_url ist tatsächlich auf http://localhost:3000 gesetzt. Ich vermute, dass der RetrieveTopic-Job irgendwo stillschweigend fehlschlägt, und versuche herauszufinden, wo genau. Es gibt keine Fehlerprotokolle in /logs, und /sidekiq enthält weder Verweise auf das Abrufen von Themen noch Protokolle irgendeiner Art.

Entschuldigung, ich habe im Moment keine weiteren Ideen. Da der Code in der Produktion aktuell funktioniert, liegt das Problem wahrscheinlich an der Umgebung, einem Plugin oder einer Konfiguration.

1 „Gefällt mir“

Hallo, danke für die Untersuchung. Ich glaube, ich habe exakt das gleiche Problem (die Einbettung funktioniert für bestehende Themen, schlägt aber bei der Erstellung eines neuen Themas fehl). Das funktioniert in meiner Produktionsumgebung, aber nicht auf meinem Dev-Machine.

Mein Setup ist ein Docker-Stack, und ich habe sichergestellt, dass alles sowohl von Discourse als auch von Sidekiq erreichbar ist. Im Moment fange ich an zu denken, dass Discourse beim Parsen einer URL (was auch fehlschlägt, wenn Onebox versucht, eine Vorschau eines Links in einem Beitrag abzurufen) irgendwie von einem externen Dienst abhängt, der lokale Instanzen nicht sehen kann… Wäre das möglich?

@wilson29thid, hast du seitdem auf deiner Seite etwas gefunden?

Ich bin auf demselben Problem auf meiner Produktionsmaschine gestoßen, nicht auf meiner Entwicklermaschine. Irgendetwas lässt mich denken, dass es nicht genau darauf ankommt, welche du verwendest.

1 „Gefällt mir“

Nein, ich fürchte, ich habe das nie herausgefunden und habe stattdessen die Discourse-API genutzt, um manuell ein Thema zu erstellen :pensive_face:

1 „Gefällt mir“

Das könnte ich auch machen. Das Gute ist, dass du die Anzahl der Threads steuern kannst, die erstellt werden, bevor die Leute anfangen, deine Artikel zu kommentieren.