Yt.w
2024 年10 月 27 日 06:27
1
lib/highlight_js.rb 中的以下代码在某些域上有效,但在其他域上无效:
def self.path
"/highlight-js/#{Discourse.current_hostname}/#{version SiteSetting.highlighted_languages}.js"
end
我有两个 Discourse 站点。此代码在域 www.abc.com 上有效,但在 efg.com 上无效。在浏览器控制台中,我看到以下错误:
formatter.js:383 Uncaught (in promise) TypeError: Failed to resolve module specifier '/highlight-js/efg.com/9797975efac87d28baa695ae13ca72ccaf5120f5.js'. The base URL is about:blank because import() is called from a CORS-cross-origin script.
在对 highlight_js.rb 中的 self.path 进行如下修改后:
def self.path
"https://#{Discourse.current_hostname}/highlight-js/#{Discourse.current_hostname}/#{version SiteSetting.highlighted_languages}.js"
end
该问题已解决。
看起来使用相对路径,如
import('/highlight-js/efg.com/9797975efac87d28baa695ae13ca72ccaf5120f5.js')
会导致 CORS 问题,而使用绝对 URL,
import('https://efg.com/highlight-js/efg.com/9797975efac87d28baa695ae13ca72ccaf5120f5.js')
则可以正常工作。
1 个赞
奇怪的是,它在 abc.com 下可以工作,但在 efg.com 下卻不行,因為這兩個不同的路由是完全不同的
Yt.w
2024 年10 月 27 日 09:04
3
我的意思是它适用于 www.abc.com 但不适用于 efg.com,不确定为什么,但它发生在我的案例中
1 个赞
simonk
(Simon King)
2024 年10 月 28 日 11:49
4
您是否在这两个网站上使用了 CDN?我注意到我的网站上的代码高亮已不再有效,我认为这是因为:
The change which made this noticeable was most likely DEV: Modernise highlightjs loading (#24197) · discourse/discourse@0878dde · GitHub , which switched highlightjs to load via native import(), which requires CORS headers when fetching from a CDN.
But even before that change, you likely would have had some issues with things like custom Fonts (which also require CORS headers for cross-origin requests).
In theory, Discourse itself should be adding the CORS header to CDN responses. If it’s not, …
就我而言,我的 CDN 没有 为 highlightjs 文件返回 Access-Control-Allow-Origin 标头。我注意到 Meta 的 CDN 确实 包含该标头,所以我想知道有什么不同。
$ curl --silent -I https://d3bpeqsaub0i6y.cloudfront.net/highlight-js/meta.discourse.org/9797975efac87d28baa695ae13ca72ccaf5120f5.js | grep -i access-control
access-control-allow-origin: *
access-control-allow-methods: GET, HEAD, OPTIONS
但是,这些标头没有 由源服务器提供:
$ curl --silent -I https://meta.discourse.org/highlight-js/meta.discourse.org/9797975efac87d28baa695ae13ca72ccaf5120f5.js | grep -i access-control
据我所知,Discourse 应该为 highlightjs 文件添加访问控制标头:
# frozen_string_literal: true
class HighlightJsController < ApplicationController
skip_before_action :preload_json,
:redirect_to_login_if_required,
:redirect_to_profile_if_required,
:check_xhr,
:verify_authenticity_token,
only: [:show]
before_action :apply_cdn_headers, only: [:show]
def show
no_cookies
RailsMultisite::ConnectionManagement.with_hostname(params[:hostname]) do
current_version = HighlightJs.version(SiteSetting.highlighted_languages)
return redirect_to path(HighlightJs.path) if current_version != params[:version]
# note, this can be slightly optimised by caching the bundled file, it cuts down on N reads
但是 ,只有当请求是“CDN 请求”时,这些标头才会被应用:
return unless mini_profiler_enabled?
Rack::MiniProfiler.authorize_request
end
def check_xhr
# bypass xhr check on PUT / POST / DELETE provided api key is there, otherwise calling api is annoying
return if !request.get? && (is_api? || is_user_api?)
raise ApplicationController::RenderEmpty.new if !request.format&.json? && !request.xhr?
end
def apply_cdn_headers
if Discourse.is_cdn_request?(request.env, request.method)
Discourse.apply_cdn_headers(response.headers)
end
end
def self.requires_login(arg = {})
@requires_login_arg = arg
end
def self.requires_login_arg
end
mattr_accessor :redis
def self.is_parallel_test?
ENV["RAILS_ENV"] == "test" && ENV["TEST_ENV_NUMBER"]
end
CDN_REQUEST_METHODS ||= %w[GET HEAD OPTIONS]
def self.is_cdn_request?(env, request_method)
return if CDN_REQUEST_METHODS.exclude?(request_method)
cdn_hostnames = GlobalSetting.cdn_hostnames
return if cdn_hostnames.blank?
requested_hostname = env[REQUESTED_HOSTNAME] || env[Rack::HTTP_HOST]
cdn_hostnames.include?(requested_hostname)
end
def self.apply_cdn_headers(headers)
这仅在 Discourse 配置了单独的“CDN 请求”主机名时才有效。
1 个赞
simonk
(Simon King)
2024 年10 月 28 日 12:02
5
有一个设置 cdn_origin_hostname,或许可以设置为普通的 discourse 主机名:
# authorization key that will be included as a header in requests made by the
# snapshots transporter to the URL specified above. The destination should
# know this key and only accept requests that have this key in the
# `Mini-Profiler-Transport-Auth` header.
mini_profiler_snapshots_transport_auth_key =
# recommended, cdn used to access assets
cdn_url =
# The hostname used by the CDN to request assets
cdn_origin_hostname =
# comma delimited list of emails that have developer level access
developer_emails =
# redis server address
redis_host = localhost
# redis server port
redis_port = 6379
我认为这会使 is_cdn_request 检查通过,但我不知道是否会有任何负面影响。
Yt.w
2024 年10 月 28 日 12:48
6
Simon King:
您是否在这两个网站上使用了 CDN?
是的,我在 efg.com 上使用 CDN,但当我访问 js 文件时,它确实返回了我正确的 Access-Control-Allow-Origin ,这让我很困惑。
simonk
(Simon King)
2024 年10 月 29 日 17:48
7
作为后续,我将 cdn_origin_hostname 设置为我的 Discourse 实例的常规域名,刷新了 CDN 缓存,现在 highlightjs 又可以正常工作了。我还没有注意到 任何副作用……