لا يمكنني تشغيل التضمين

مرحبًا، أحاول تضمين تعليقات Discourse على موقعي الإلكتروني، تاركًا دليل التضمين، وقد اصطدمت بحائط :frowning:

الأعراض

لقد جربت ذلك في Firefox و Chrome. في كلتا الحالتين، يتم تحميل إطار Discourse “جاري تحميل النقاش…” لكنه يتوقف هناك، مع ظهور أخطاء JavaScript متكررة في وحدة تحكم المطور.

في Firefox، أحصل على خطأ يتعلق بـ X-Frame-Options:

تم العثور على رأس X-Frame-Options غير صالح عند تحميل "https://discourse.29th.local/embed/comments?embed_url=https%3A%2F%2Fpersonnel.29th.local%2F%23enlistments%2F11927": "ALLOWALL" ليس توجيهًا صالحًا.

يلي ذلك خطأ DOMException في embed-application.js:7:

Uncaught DOMException: تم تحديد سلسلة غير صالحة أو غير قانونية

يتكرر هذان الخطآن كل 30 ثانية تقريبًا. لا توجد طلبات فاشلة في تبويب الشبكة.

في Chrome، لا أحصل على خطأ X-Frame-Options. بعد بضع ثوانٍ، أحصل على خطأ يتعلق بعدم تطابق الأصل المستهدف مع أصل نافذة المستلم:

فشل تنفيذ 'postMessage' على 'DOMWindow': الأصل المستهدف المقدم ('https://discourse.29th.local') لا يتطابق مع أصل نافذة المستلم ('https://personnel.29th.local').

لقد رأيت العديد من المواضيع على meta حول هذا الخطأ، وحاولت جميع خطوات استكشاف الأخطاء وإصلاحها، دون جدوى.

إعداداتي

لقد اتبعت دليل إعداد Discourse لنظام Mac مع استثناء طفيف: بدلاً من تثبيت postgres و redis و mailcatcher بشكل عام على جهاز الكمبيوتر المحمول الخاص بي، أقوم بتشغيلها في حاويات Docker، مع تعريض المنافذ علنًا. لا يعرف Discourse أنها تعمل في حاويات Docker بدلاً من الأجهزة المادية. Rails/discourse مثبت بشكل عام ولا يعمل في حاوية Docker.

بشكل منفصل تمامًا، يعمل تطبيق الويب المخصص الخاص بي في مكدس Docker Compose. يتضمن جزء من هذا المكدس خادم nginx يقوم بتوجيه personnel.29th.local إلى الحاوية الصاعدة المناسبة، و discourse.29th.local إلى host.docker.internal:3000 (هذا هو اسم المضيف السحري الذي يمكن لحاويات Docker استخدامه للوصول إلى localhost للمضيف).

(كما أذكر أدناه، أزلت طبقة nginx من المعادلة وانتهيت بنفس الخطأ)

قد تكون هناك مشكلة محتملة هنا وهي أن تطبيق الويب الخاص بي هو تطبيق صفحة واحدة (SPA) بلغة JavaScript. الصفحة التي يتم تضمين تعليقات Discourse فيها هي https://personnel.29th.local/#enlistments/1234 ولا يوجد عرض من جانب الخادم. إذا كانت هذه مشكلة، كنت أتوقع خطأً مع الزاحف، وعندها سأكتفي بـ Discourse بالربط بتطبيقي بدلاً من زحفه. لكن الأخطاء التي تظهر لا تبدو مرتبطة بفشل الزحف.

استكشاف الأخطاء وإصلاحها

لقد قمت بتعيين المضيف القابل للتضمين في Admin > Customize > Embedding إلى personnel.29th.local. في البداية، أظهرت كود التضمين النموذجي http://localhost:3000/ لـ discourseUrl، لذا شغلت rails console وقمت بتشغيل:

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

وقمت بتفعيل “force https” في لوحة تحكم المسؤول. هذا أصلح الرابط في كود التضمين النموذجي.

لقد أضفت أيضًا https://personnel.29th.local كمجال CORS في قسم cors origins في الإعدادات.

أنا الآن أبدأ تشغيل Discourse بالأمر التالي:

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

كما جربت تعطيل سياسة محتوى الأمان (Content Security Policy) في لوحة تحكم الإعدادات.

لقد نظرت في https://discourse.29th.local/logs/ لكنني لم أر أي أخطاء، ولا شيء يتعلق بـ Sidekiq.

بخصوص Sidekiq، لدي رسالة في لوحة تحكم المسؤول حول التحديثات:

لم يتم إجراء فحص للتحديثات. تأكد من تشغيل sidekiq.

لذلك قمت بتشغيل Sidekiq.redis { |r| puts r.flushall } في وحدة تحكم rails وحصلت على OK، ثم أعيدت تشغيل خادم rails، ولم يتغير شيء في الرسالة ولا في المشكلة العامة. لقد تلمست حول ذاكرة التخزين المؤقت لـ redis ولم أر أي شيء يتعلق بهذه الصفحة.

كما حاولت تبسيط الأمور بإخراج طبقة nginx من المعادلة: إعادة تعيين SiteSetting.force_hostname و SiteSetting.port إلى nil، وإيقاف تشغيل force https، والوصول إلى تطبيق الويب الخاص بي و Discourse عبر localhost، وإضافة تطبيق الويب الخاص بي إلى المضيفين القابلين للتضمين واسمات المضيفين CORS في Discourse (http://localhost:8080)، لكنني حصلت على نفس الخطأ، فقط مع مضيفات مختلفة:

فشل تنفيذ 'postMessage' على 'DOMWindow': الأصل المستهدف المقدم ('http://localhost:3000') لا يتطابق مع أصل نافذة المستلم ('http://localhost:8080').

أنا أعمل بالإصدار 2.6.0.beta6 ( 60bc38e6a8 )، الذي حصلت عليه عن طريق نسخ فرع master حسب دليل إعداد Discourse لنظام Mac قبل بضعة أسابيع وتشغيل git pull origin master اليوم.

لقد قمت أيضًا بإزالة مجلد tmp وأعدت تشغيل الخادم.

لقد خرجت أيضًا في نزهة، صرخت في وسادة، وبكيت تحت طاولتي.

أرجو أن يكون هذا يغطي جميع الجوانب. آمل أن يتمكن أحدكم من المساعدة!

آسف لسماع أنك تواجه صعوبة كبيرة في الإعداد.

Discourse ليس ذكياً بما يكفي لزحف تطبيق الصفحة الواحدة (SPA)، لذا يبدو هذا الاحتمال الأكثر ترجيحاً بالنسبة لي. هل يمكنك محاولة إعادة إنتاج المشكلة باستخدام موقع يحتوي على محتوى ثابت؟

من المستحيل علينا دعم كل تثبيت مخصص، لذا أنصحك بمحاولة تبسيط مجموعة الأدوات الخاصة بك أكثر حتى يعمل، ثم إضافة الأجزاء الأخرى تدريجياً من هناك.

3 إعجابات

شكرًا لك على ردك، ولا تقلق، فأنا أعرف أن الأمر يستحق العناء!

لقد قمتُ بتبسيط الأمور باستخدام موقع يتم عرضه بواسطة الخادم (rails) وحذف طبقة nginx تمامًا. يعمل تطبيقي على المنفذ 3001 بينما يعمل discourse على المنفذ 3000.

يتم عرض كود التضمين الخاص بي على النحو التالي:

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

لقد أضفتُ localhost:3001 إلى المضيفات القابلة للتضمين في _Admin > Customize > Embedding، وأضفتُ http://localhost:3001` إلى أسماء المضيفات في Admin > Settings > cors.

الخطأ هو نفسه، ولكن مع تحديث أسماء المضيفات:

فشل تنفيذ 'postMessage' على 'DOMWindow': الأصل المستهدف المقدم ('http://localhost:3000') لا يتطابق مع أصل نافذة المستلم ('http://localhost:3001').

المكدس بسيط للغاية الآن :thinking: أفترض أن هذا يعني أنه مشكلة في التكوين من نوع ما؟ هل لديك أي أفكار؟

بعض نتائج التصحيح الإضافية:

لقد قمت بإنشاء موضوع يدويًا واستبدلت discourseEmbedUrl: 'http://localhost:3001/enlistments/<%= @enlistment.id %>' بـ topicId: 14 في مقتطف جافا سكريبت الخاص بي، وتم تحميل التعليقات. هذا يشير إلى أن المشكلة ليست في CORS أو X-Frame، بل (أ) شيء يتعلق بالزحف (scraping)، و (ب) ربما مشكلة في كيفية معالجة الأخطاء أثناء التضمين.

لفحص مشكلة الزحف، قمت بزيارة صفحة جديدة لم أحاول الوصول إليها من قبل (وبالتالي لم يتم محاولة الزحف عليها). راقبت وحدة تحكم Rails الخاصة بتطبيقني وقمت بتحميل الصفحة. رأيت /enlistments/6 في السجل مرة واحدة. انتظرت حتى ظهر رسالة الخطأ في وحدة تحكم جافا سكريبت، وبحلول ذلك الوقت كان يجب أن يكون Discourse قد حاول الزحف، لكن وحدة تحكم Rails الخاصة بتطبيقني لم تظهر أي سجلات محاولات وصول أخرى.

لم تكن هناك أخطاء في نقطة نهاية /logs الخاصة بـ Discourse، ولا أي شيء يمكنني تمييزه في سجل Rails الخاص بـ Discourse.

ظننت أن Discourse ربما لا يستطيع الوصول إلى موقعي الإلكتروني، لذا سجلت الدخول إلى وحدة تحكم Rails في تطبيق Discourse الخاص بي وقمت بتشغيل:

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

أثناء فعل ذلك، رأيت سجل الوصول في خادم Rails الخاص بتطبيقني. هذا يؤكد أن Discourse يستطيع الوصول إلى تطبيقنا.

الآن أعتقد أن المشكلة يجب أن تكون متعلقة بـ Sidekiq أو جدولة المهام؟ :man_shrugging: لكنني لست متأكدًا من كيفية تصحيح ذلك. لم أستخدم Sidekiq من قبل.

نظرت مرة أخرى في بيانات Redis (باستخدام TablePlus، وهو واجهة رسومية لقاعدة بيانات تعمل مع Redis)، وأرى حوالي 3 صفوف بمفتاح key بقيم مثل default:logster-env-96404aef1da0c422fc32e3bb82d85fbc وقيمة value بقيم مثل

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

النوع type هو LIST ووقت انتهاء الصلاحية ttl هو -1. أعتقد أن هذا يعني أن المهمة قيد البدء؟

لقد تجولت في /sidekiq لكنني لا أرى أي ذكر لهذه المهمة ولا أي نوع من الطابور يُسمى RetrieveTopic :frowning:

أضيق نطاق المشكلة بالتأكيد لكنني أحتاج إلى مساعدة إذا خطرت لك أي فكرة!

مرحبًا @eviltrout، هل لديك أي أفكار لاستكشاف الأخطاء وإصلاحها بشكل أكبر، الآن بعد أن قمت بتبسيط الإعداد إلى الأساسيات؟

من المؤكد تقريبًا أن المشكلة تتعلق بالإعدادات. ربما يعتقد نظام Discourse الخاص بك في localhost:3000 أن لديه اسم مضيف مختلف. يمكنك التحقق من ذلك عبر وحدة التحكم باستخدام:

Discourse.base_url

أمر آخر يجب التحقق منه هو سجلات sidekiq في /sidekiq.

@eviltrout لقد أضفت أسطرًا للتصحيح إلى مكتبة TopicRetriever، وأكدت أن invalid_url? تساوي false (مما يشير إلى أنها صالحة). في الواقع، تم تعيين Discourse.base_url إلى http://localhost:3000. أعتقد أن مهمة RetrieveTopic تفشل بصمت في مكان ما، وأنا أحاول تتبع المكان. لا توجد سجلات أخطاء في /logs، ولا يحتوي /sidekiq على أي إشارة إلى استرداد المواضيع أو سجلات من أي نوع.

عذرًا، ليس لدي أي أفكار أخرى في الوقت الحالي. أعلم أن الكود يعمل حاليًا في بيئة الإنتاج، لذا فهناك مشكلة تتعلق بالبيئة أو بإحدى الإضافات أو بالإعدادات.

إعجاب واحد (1)

مرحبًا، شكرًا على التحقيق. أعتقد أنني أواجه نفس المشكلة تمامًا (التضمين يعمل للمواضيع الموجودة لكنه يفشل عند إنشاء موضوع جديد). هذا يعمل في بيئتي الإنتاجية لكن لا يعمل على جهاز التطوير الخاص بي.

إعدادي عبارة عن مكدس Docker، وقد تأكدت من أن كل شيء مرئي من كلا Discourse و Sidekiq. في هذه المرحلة، بدأت أظن أنه عندما يحاول Discourse تحليل عنوان URL (يفشل أيضًا عندما يحاول Onebox جلب معاينة لرابط في منشور)، فإنه يعتمد بطريقة ما على خدمة خارجية تفشل في رؤية المثيلات المحلية… هل هذا ممكن؟

@wilson29thid هل عثرت على أي شيء من جانبك منذ ذلك الحين؟

واجهتُ نفس المشكلة على جهاز الإنتاج الخاص بي، وليس على جهاز المطور. هناك شيء ما يجعلني أعتقد أنه لا يهم حقًا أيهما تستخدم.

إعجاب واحد (1)

لا، أخشى أنني لم أستطع حل هذه المشكلة قط، وانتهى بي الأمر باستخدام واجهة برمجة تطبيقات discourse لإنشاء موضوع يدويًا :pensive_face:

إعجاب واحد (1)

قد أفعل ذلك أنا أيضًا. الميزة الجيدة هي أنه يمكنك التحكم في عدد الخيوط التي يتم إنشاؤها قبل أن يبدأ الناس في التعليق على مقالاتك…