Impossibile far funzionare l'embedding

Ciao, sto cercando di incorporare i commenti di Discourse sul mio sito web seguendo la guida all’incorporamento, ma mi sono imbattuto in un muro :frowning:

Sintomi

Ho provato su Firefox e Chrome. In entrambi i casi, viene caricato l’iframe di Discourse con il messaggio “Caricamento discussione…”, ma si blocca lì, con errori JavaScript ricorrenti nella console per sviluppatori.

Su Firefox, ricevo un errore relativo a X-Frame-Options:

È stato rilevato un header X-Frame-Options non valido durante il caricamento di “https://discourse.29th.local/embed/comments?embed_url=https%3A%2F%2Fpersonnel.29th.local%2F%23enlistments%2F11927”: “ALLOWALL” non è una direttiva valida.

Seguito da un errore DOMException in embed-application.js:7:

Uncaught DOMException: È stata specificata una stringa non valida o illegale

Questi due errori si ripetono ogni 30 secondi circa. Non ci sono richieste fallite nella scheda di rete.

Su Chrome, non ricevo l’errore X-Frame-Options. Dopo alcuni secondi, ottengo un errore relativo all’origine di destinazione che non corrisponde all’origine della finestra destinataria:

Impossibile eseguire 'postMessage' su 'DOMWindow': l'origine di destinazione fornita ('https://discourse.29th.local') non corrisponde all'origine della finestra destinataria ('https://personnel.29th.local').

Ho visto molti argomenti su meta riguardanti questo errore e ho provato tutti i passaggi di risoluzione dei problemi, senza successo.

La mia configurazione

Ho seguito la guida all’installazione di Discourse per Mac con una leggera eccezione: invece di installare postgres, redis e mailcatcher globalmente sul mio laptop, li ho eseguiti in container Docker, con le porte esposte pubblicamente. Discourse non sa che sono in esecuzione in container Docker invece che su hardware dedicato. Rails/Discourse è installato globalmente e non è in esecuzione in un container Docker.

Completamente separatamente, la mia applicazione web personalizzata è in esecuzione in uno stack Docker Compose. Parte di quello stack include un server nginx che instrada personnel.29th.local al container upstream appropriato e discourse.29th.local a host.docker.internal:3000 (questo è l’hostname magico che i container Docker possono utilizzare per raggiungere la localhost dell’host).

(Come accenno di seguito, ho rimosso il livello nginx dall’equazione e ho ottenuto lo stesso errore)

Un possibile problema qui è che la mia app web è una single page application JavaScript. La pagina in cui vengono incorporati i commenti di Discourse è https://personnel.29th.local/#enlistments/1234 e non c’è rendering lato server. Se questo fosse un problema, mi aspetterei un errore con il crawler, nel qual punto mi accontenterei che Discourse si limitasse a creare un link alla mia app invece di scansionarla. Ma gli errori che mostra non sembrano correlati a fallimenti di scansione.

Risoluzione dei problemi

Ho impostato l’host incorporabile in Admin > Personalizza > Incorporamento su personnel.29th.local. All’inizio, il codice di esempio per l’incorporamento mostrava http://localhost:3000/ per discourseUrl, quindi ho avviato rails console ed eseguito:

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

E ho attivato “forza https” nella dashboard di amministrazione. Questo ha corretto l’URL nel codice di esempio per l’incorporamento.

Ho anche aggiunto https://personnel.29th.local come dominio CORS nella sezione cors origins delle impostazioni.

Ora sto avviando Discourse con il seguente comando:

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

Ho anche provato a disabilitare la Content Security Policy nella dashboard delle impostazioni.

Ho controllato su https://discourse.29th.local/logs/ ma non ho visto errori e nulla riguardo a Sidekiq.

A proposito di Sidekiq, ho un messaggio sulla dashboard di amministrazione sugli aggiornamenti:

Non è stata eseguita una verifica degli aggiornamenti. Assicurati che Sidekiq sia in esecuzione.

Quindi ho eseguito Sidekiq.redis { |r| puts r.flushall } nella console di rails e ho ottenuto OK, ho riavviato il server rails e non ci sono state modifiche al messaggio né al problema complessivo. Ho dato un’occhiata alla cache di redis e non ho visto nulla relativo a questa pagina.

Ho anche tentato di semplificare le cose rimuovendo il livello nginx dall’equazione: ripristinando SiteSetting.force_hostname e SiteSetting.port a nil, disattivando force https, accedendo alla mia app web e a Discourse tramite localhost, e aggiungendo la mia app web agli host incorporabili e ai nomi host CORS di Discourse (http://localhost:8080), ma ho ottenuto lo stesso errore, solo con host diversi:

Impossibile eseguire 'postMessage' su 'DOMWindow': l'origine di destinazione fornita ('http://localhost:3000') non corrisponde all'origine della finestra destinataria ('http://localhost:8080').

Sto eseguendo la versione 2.6.0.beta6 ( 60bc38e6a8 ), che ho ottenuto clonando il ramo master come indicato nella guida all’installazione di Discourse per Mac un paio di settimane fa ed eseguendo git pull origin master oggi.

Ho anche rimosso la directory tmp e riavviato il server.

Ho anche fatto una passeggiata, urlato contro un cuscino e pianto sotto la mia scrivania.

Spero che questo copra tutti gli aspetti. Spero che qualcuno possa aiutarmi!

Mi dispiace sentire che stai avendo così tante difficoltà nella configurazione.

Discourse non è abbastanza intelligente da eseguire il crawling di una SPA, quindi questa mi sembra la causa più probabile. Puoi provare a riprodurre il problema con un sito che contiene contenuti statici?

È impossibile per noi supportare ogni installazione personalizzata, quindi ti consiglio di semplificare ulteriormente il tuo stack finché non funziona, per poi aggiungere altri componenti da lì.

Grazie per la risposta, e non preoccuparti, so che ne varrà la pena!

Ho semplificato le cose utilizzando un sito renderizzato lato server (Rails) e rimuovendo completamente il livello nginx. Ho l’app in esecuzione sulla porta 3001 e Discourse sulla porta 3000.

Il mio codice di embedding viene renderizzato così:

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

Ho aggiunto localhost:3001 agli host embeddabili in Admin > Personalizza > Embedding e http://localhost:3001 ai nomi host in Admin > Impostazioni > cors.

L’errore è lo stesso, ma con i nomi host aggiornati:

Impossibile eseguire 'postMessage' su 'DOMWindow': l'origine target fornita ('http://localhost:3000') non corrisponde all'origine della finestra di destinazione ('http://localhost:3001').

Lo stack è ora il più semplice possibile :thinking: Immagino che significhi che si tratta di un problema di configurazione di qualche tipo? Hai qualche idea?

Alcuni ulteriori riscontri sul debug:

Ho creato manualmente un argomento e ho sostituito discourseEmbedUrl: 'http://localhost:3001/enlistments/<%= @enlistment.id %>' con topicId: 14 nel mio frammento JavaScript, e i commenti si sono caricati. Ciò suggerisce che non si tratta di un problema CORS o X-Frame-, ma (a) di qualcosa legato allo scraping e (b) possibilmente di un problema relativo alla gestione degli errori durante l’embedding.

Per indagare sul problema dello scraping, ho visitato una nuova pagina a cui non avevo mai cercato di accedere prima (e quindi non era stato tentato alcuno scraping su di essa). Ho osservato la console rails della mia applicazione e ho caricato la pagina. Ho visto /enlistments/6 nei log una sola volta. Ho aspettato che il messaggio di errore venisse generato nella console JavaScript, momento in cui Discourse avrebbe dovuto aver tentato lo scraping, ma la console rails della mia applicazione non ha mostrato altri log di tentativi di accesso.

Non c’erano errori nell’endpoint /logs di Discourse, né alcuno che potessi individuare nel log rails di Discourse.

Ho pensato che forse Discourse non potesse accedere al mio sito web, quindi ho effettuato l’accesso alla console rails sulla mia applicazione Discourse e ho eseguito:

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

Mentre lo facevo, ho visto il log di accesso nel server rails della mia applicazione. Questo ha confermato che Discourse può raggiungere la mia applicazione.

Ora penso che debba essere un problema legato a Sidekiq o alla pianificazione dei job? :man_shrugging: Non sono sicuro di come debuggarlo, però. Non ho mai usato Sidekiq prima d’ora.

Ho dato un’altra occhiata ai dati Redis (usando TablePlus, un’interfaccia grafica per database che funziona con Redis) e vedo circa 3 righe con una key di valori come default:logster-env-96404aef1da0c422fc32e3bb82d85fbc e un value con valori come

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

il type è LIST e il ttl è -1. Immagino che significhi che il job viene avviato?

Ho dato un’occhiata in /sidekiq ma non vedo alcun riferimento a questo job né alcun tipo di coda chiamata RetrieveTopic :frowning:

Sto sicuramente restringendo il campo, ma potrei aver bisogno di un aiuto se vi viene in mente qualcosa!

Ehi @eviltrout, hai qualche idea per ulteriori diagnosi, ora che ho semplificato la configurazione ai minimi termini?

È quasi certamente un problema di configurazione. Forse il tuo Discourse su localhost:3000 pensa di avere un nome host diverso. Puoi verificare da una console usando:

Discourse.base_url

Un’altra cosa da controllare sono i log di sidekiq in /sidekiq.

@eviltrout Ho aggiunto alcune righe di debug alla libreria TopicRetriever e ho confermato che invalid_url? è false (il che suggerisce che l’URL è valido). Discourse.base_url è effettivamente impostato su http://localhost:3000. Credo che il job RetrieveTopic stia fallendo silenziosamente da qualche parte e sto cercando di individuare dove. Non ci sono log di errore in /logs e /sidekiq non contiene alcun riferimento al recupero dei topic o log di alcun tipo.

Mi dispiace, al momento non ho altre idee. So che il codice funziona attualmente in produzione, quindi deve trattarsi di un problema ambientale, di un plugin o di configurazione.

Ciao, grazie per l’indagine. Credo di avere esattamente lo stesso problema (l’embedding funziona per gli argomenti esistenti ma fallisce durante la creazione di un nuovo argomento). Questo funziona nel mio ambiente di produzione ma non sulla mia macchina di sviluppo.

La mia configurazione è uno stack Docker e ho assicurato che tutto fosse visibile sia da Discourse che da Sidekiq. A questo punto, comincio a pensare che quando Discourse tenta di analizzare un URL (fallisce anche quando Onebox prova a recuperare un’anteprima di un link in un post), in qualche modo dipende da un servizio esterno che non riesce a vedere le istanze locali… Sarebbe possibile?

@wilson29thid, hai trovato qualcosa dalla tua parte da allora?

Ho riscontrato lo stesso problema sulla mia macchina di produzione, non su quella di sviluppo. Qualcosa mi fa pensare che non faccia davvero differenza quale delle due tu stia utilizzando.

No, temo che non ci sia mai riuscito e ho finito per usare l’API di Discourse per creare un argomento manualmente :pensive_face:

Potrei farlo anch’io. Il bello è che puoi controllare il numero di thread creati prima che le persone inizino a commentare i tuoi articoli…