JS 임베드가 "Job exception: invalid stored block lengths (Zlib::DataError)" 오류로 실패합니다

안녕하세요, 저희 환경에서 JS 임베드를 작동시킬 수 없습니다. 다른 유사한 주제들을 모두 읽어보았고, 과거에 완전히 다른 프로젝트에서는 이 임베드를 성공적으로 작동시킨 적이 있습니다. 이번에는 뭔가 다른 문제가 있는 것 같습니다…

외부 사이트에서는 로고만 표시된 후 "loading discussion…"라는 메시지가 나타납니다.

Discourse에서는 요청이 들어오고 있다는 내용이 에러 로그에 표시되더라도 아무 주제도 생성되지 않습니다.

URL들을 확인해 보았습니다. 또한 변수 대신 정적 URL을 추가하는 것도 테스트해 보았습니다. 아무런 변화가 없습니다.

Discourse 에러 로그에는 다음과 같은 에러가 있습니다:

Job exception: invalid stored block lengths (Zlib::DataError)  
excon-0.88.0/lib/excon/middlewares/decompress.rb:23:in `inflate'

excon-0.88.0/lib/excon/middlewares/decompress.rb:23:in `response_call'

excon-0.88.0/lib/excon/middlewares/base.rb:26:in `response_call'

excon-0.88.0/lib/excon/middlewares/instrumentor.rb:44:in `response_call'

excon-0.88.0/lib/excon/middlewares/base.rb:26:in `response_call'

excon-0.88.0/lib/excon/middlewares/expects.rb:20:in `response_call'

excon-0.88.0/lib/excon/middlewares/response_parser.rb:12:in `response_call'

excon-0.88.0/lib/excon/connection.rb:451:in `response'

excon-0.88.0/lib/excon/connection.rb:282:in `request'

excon-0.88.0/lib/excon.rb:250:in `get'

/var/www/discourse/lib/final_destination.rb:206:in `public_send'

/var/www/discourse/lib/final_destination.rb:206:in `resolve'

/var/www/discourse/app/models/topic_embed.rb:120:in `find_remote'

/var/www/discourse/app/models/topic_embed.rb:192:in `import_remote'

/var/www/discourse/lib/topic_retriever.rb:52:in `fetch_http'

/var/www/discourse/lib/topic_retriever.rb:39:in `perform_retrieve'

/var/www/discourse/lib/topic_retriever.rb:12:in `retrieve'

/var/www/discourse/app/jobs/regular/retrieve_topic.rb:15:in `execute'

/var/www/discourse/app/jobs/base.rb:232:in `block (2 levels) in perform'

rails_multisite-4.0.0/lib/rails_multisite/connection_management.rb:80:in `with_connection'

/var/www/discourse/app/jobs/base.rb:221:in `block in perform'

/var/www/discourse/app/jobs/base.rb:217:in `each'

/var/www/discourse/app/jobs/base.rb:217:in `perform'

sidekiq-6.3.1/lib/sidekiq/processor.rb:196:in `execute_job'

sidekiq-6.3.1/lib/sidekiq/processor.rb:164:in `block (2 levels) in process'

sidekiq-6.3.1/lib/sidekiq/middleware/chain.rb:138:in `block in invoke'

/var/www/discourse/lib/sidekiq/pausable.rb:138:in `call'

sidekiq-6.3.1/lib/sidekiq/middleware/chain.rb:140:in `block in invoke'

sidekiq-6.3.1/lib/sidekiq/middleware/chain.rb:143:in `invoke'

sidekiq-6.3.1/lib/sidekiq/processor.rb:163:in `block in process'

sidekiq-6.3.1/lib/sidekiq/processor.rb:136:in `block (6 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/job_retry.rb:112:in `local'

sidekiq-6.3.1/lib/sidekiq/processor.rb:135:in `block (5 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq.rb:39:in `block in <module:Sidekiq>'

sidekiq-6.3.1/lib/sidekiq/processor.rb:131:in `block (4 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/processor.rb:257:in `stats'

sidekiq-6.3.1/lib/sidekiq/processor.rb:126:in `block (3 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/job_logger.rb:13:in `call'

sidekiq-6.3.1/lib/sidekiq/processor.rb:125:in `block (2 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/job_retry.rb:79:in `global'

sidekiq-6.3.1/lib/sidekiq/processor.rb:124:in `block in dispatch'

sidekiq-6.3.1/lib/sidekiq/logger.rb:11:in `with'

sidekiq-6.3.1/lib/sidekiq/job_logger.rb:33:in `prepare'

sidekiq-6.3.1/lib/sidekiq/processor.rb:123:in `dispatch'

sidekiq-6.3.1/lib/sidekiq/processor.rb:162:in `process'

sidekiq-6.3.1/lib/sidekiq/processor.rb:78:in `process_one'

sidekiq-6.3.1/lib/sidekiq/processor.rb:68:in `run'

sidekiq-6.3.1/lib/sidekiq/util.rb:43:in `watchdog'

sidekiq-6.3.1/lib/sidekiq/util.rb:52:in `block in safe_thread'

이 에러 메시지를 검색해 보았지만 여기에서도, 인터넷의 다른 곳에서도 아무것도 나오지 않습니다.

어떤 힌트를 주실 수 있을까요?

페이지 압축과 관련된 오류인 것 같습니다. 임베드하려는 페이지 링크를 공유해 주시겠어요?

확인해 주셔서 감사합니다!

이것이 외부 페이지입니다: Bitwig Preset: Phase-3 | Bitwiggers

그리고 주제(topic)가 표시되어야 하는 카테고리입니다: Bitwiggers.com - Bitwish

(테스트 실패 후 템플릿을 제거했습니다.)

이 코멘트가 도움이 될까요? (제 기술 수준을 벗어난 내용입니다):

응답은 모두 성공적인 200 상태 코드이며, 해당 토론에 따르면 Bitwiggers를 스크래핑할 때 해당 응답을 처리하는 데 실패하는 것 같습니다. 특히 압축을 처리하는 과정에서 실패하고 있습니다.

inflate에 따르면 deflate 압축 방식을 사용하도록 협상되었지만, 선호되는 방식은 gzip이라고 생각합니다. Firefox의 요청을 보면 두 방식 모두 처리할 수 있지만, 해당 경우 서버는 gzip을 선택합니다.

웹서버에 요청을 보내면

curl 'https://bitwiggers.com/presets/d1a7c2c7-848d-425c-9058-993317cbcc9c/' -H 'accept-encoding: deflate, gzip' -vv

이런 식으로 요청을 보내면, 대부분의 웹서버가 두 옵션 중 gzip을 선호하는 반면, deflate으로 압축된 응답을 반환합니다. 이는 이상한 현상입니다.

아래 코드로 이 오류를 쉽게 재현할 수 있음을 확인했습니다.

require 'excon'
response = Excon.get('https://bitwiggers.com/presets/d1a7c2c7-848d-425c-9058-993317cbcc9c/',
 headers: {'accept-encoding' => 'deflate, gzip'})

# 실패, excon의 기본 설정
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(response.body)

# 동작
Zlib::Inflate.new(0).inflate(response.body)

이 코드는 Excon에서 8년 이상 된 것이므로, 여기서는 웹서버 쪽에 문제가 있는 것으로 추정됩니다. 하지만 어쨌든 upstream에도 보고했습니다.

흥미롭네요, 그리고 버그를 보고해 주셔서 감사합니다. 구독했습니다.

우리의 생각을 정리해 보겠습니다:

해당 처리 방식에 대해 우리가 통제할 수 있는 권한은 없지만, 웹서버의 문제는 아닌 것 같습니다. 그렇다면 헤더 구성 방식은 어떨까요? gzip, deflate로 전달된다면 응답은 gzip으로 압축되어야 합니다. HTTP 사양에 따르면 클라이언트는 옵션을 가중치 유무와 관계없이 선호도 순서대로 제시해야 합니다. 따라서 요청에서 deflate를 gzip보다 선호한다면 deflate 인코딩을 받게 됩니다. 그렇다면 요청한 인코딩을 받았지만 이를 처리하지 못했다는 점에서, 문제의 원인은 코드/요청 자체에 있는 것 아닌가요?

아마도 이 문제와 관련이 있을까요?

여기에는 "merge"가 있고 gzip에 대한 기대치가 있는 것처럼 보입니다.

다른 서버의 관리자는 자신의 서버 측에서 gzip을 강제하는 방법을 검토하고 있습니다. 여전히 이 문제에 대해 여러분의 의견을 알고 싶습니다.

(참고로, 해당 서버는 AWS API Gateway이며, 압축 활성화/비활성화를 제외하고는 우리가 통제할 수 있는 부분이 아닙니다.)

개발자가 답변했습니다: Excon fails to inflate specific page · Issue #768 · excon/excon · GitHub

Excon 개발자의 답변을 번역해 주실 수 있을까요? 문제가 어디에 있는지, 그리고 누가 이를 수정할 수 있는지 확실하지 않습니다.

또한 이 gzip/deflate 문제를 우회하기 위해 우리 Discourse에 로컬 패치를 적용할 수 있을지 궁금합니다. 로컬 패치는 관리가 번거롭지만, 이 문제로 인해 수백 페이지에 달하는 두 사이트의 통합 기능이 Discourse 토론과 함께 임베드되지 못하는 상황은 그보다 훨씬 더 고통스럽습니다.

Excon 유지보수자가 이론적으로 이 문제를 해결하는 패치를 커밋했습니다! :tada: 그는 곧 새로운 Excon 릴리스가 나올 것이라고 말했습니다.

그리고 이제 Excon 유지보수자가 이 패치를 포함하여 라이브러리의 새 버전을 게시했습니다. :tada:

이것은 우리가 즉시 인스턴스를 업데이트할 수 있다는 뜻인가요, 아니면 Discourse가 이러한 라이브러리를 위해 자체적인 단계별 저장소를 사용하고 있는 건가요? Discourse 업그레이드 출력을 떠올려 보면, 라이브러리가 직접 업스트림 저장소에서 가져와지는 것 같지만 백엔드를 건드리기 전에 확인하고 싶습니다. :slight_smile:

결국 Discourse에 직접 물어보기로 했습니다 :slight_smile: 업그레이드 후 로그를 확인했는데,

Installing excon 0.89.0
www/discourse/vendor/bundle/ruby/2.7.0/specifications/excon-0.89.0.gemspec

이 내용을 확인한 뒤 다시 시도해 보았고, 이제 임베딩이 정상적으로 작동합니다!

@Falco 님, upstream에 보고해 주셔서 정말 감사합니다. 말씀하신 대로 옳았고, 저는 오히려 유용하지 않은 노이즈를 추가해 버렸습니다. 죄송하며, 다시 한번 감사드립니다.