Cloudfront CORS выдает обслуживание шрифтов в приложении Rails

Проблема со спящим постоянным количеством в 1 секунду после каждой передачи заключается в том, что у вас будет прерывистая производительность сети.

Пусть BandwidthMaxThreshold является искомым пределом полосы пропускания.

Пусть TransferRate является текущей скоростью передачи соединения.

Затем ...

Если вы обнаружите свой TransferRate> BandwidthMaxThreshold, вы выполните SleepTime = 1 + SleepTime * 1.02 (увеличьте время сна на 2%)

До или после каждой сетевой операции выполните Sleep (SleepTime)

Если вы обнаружите, что ваш TransferRate намного ниже, чем ваш BandwidthMaxThreshold, вы можете уменьшить время сна. В качестве альтернативы вы всегда можете разлагать / уменьшать время сна. В конце концов ваш SleepTime снова достигнет 0.

Вместо увеличения на 2% вы также можете увеличить линейное увеличение разницы между TransferRate - BandwidthMaxThreshold.

Это решение хорошо, потому что у вас не будет спит, если сеть пользователя уже не так высока, как хотелось бы.

23
задан sideshowbarker 2 February 2019 в 09:53
поделиться

3 ответа

Если вы запускаете Rails на Passenger и Heroku: (если нет, переходите прямо к ответу Ноака Магедмана)

Ответ Ноаха Магедмана был очень полезен для меня, чтобы правильно настроить CloudFront.

Я также установил rack-cors в точности так, как описано, и, хотя он работал нормально в процессе разработки, команды CURL в работе никогда не возвращали ни одной из конфигураций CORS:

curl -H "Origin: https://tidyme-staging.com.au" -I http://tidyme-staging.com.au/assets/31907B_4_0-588bd4e720d4008295dcfb85ef36b233ee0817d7fe23c76a3a543ebba8e7c85a.ttf

HTTP/1.1 200 OK
Connection: keep-alive
Server: nginx/1.10.0
Date: Wed, 03 Aug 2016 00:29:37 GMT
Content-Type: application/x-font-ttf
Content-Length: 316664
Last-Modified: Fri, 22 Jul 2016 03:31:57 GMT
Expires: Thu, 31 Dec 2037 23:55:55 GMT
Cache-Control: max-age=315360000
Cache-Control: public
Accept-Ranges: bytes
Via: 1.1 vegur

Обратите внимание, что я пингую сервер напрямую без Проходя через CDN, CDN затем после аннулирования всего контента должен просто переслать все, что ответит сервер. Важной строкой здесь является Server: nginx/1.10.0, которая указывает, что ресурсы обслуживаются nginx, а не Rails. Как следствие, конфигурации rack-cors не применяются.

Решение, которое сработало для нас, находится здесь: http://monksealsoftware.com/ruby-on-rails-cors-heroku-passenger-5-0-28/

В основном это касалось клонирования и изменения файла конфигурации nginx для Пассажира, что не является идеальным, поскольку эту копию необходимо поддерживать каждый раз, когда Пассажир обновляется и шаблон меняется.

===

Вот краткая сводка:

Перейдите в корневую папку вашего проекта Rails и сделайте копию шаблона конфигурации nginx

cp $(passenger-config about resourcesdir)/templates/standalone/config.erb config/passenger_config.erb

Откройте config/passenger_config.erb и закомментируйте эту строку

<%# include_passenger_internal_template('rails_asset_pipeline.erb', 8, false) %>

Добавьте эти конфигурации ниже указанной выше строки

### BEGIN your own configuration options ###
# This is a good place to put your own config
# options. Note that your options must not
# conflict with the ones Passenger already sets.
# Learn more at:
# https://www.phusionpassenger.com/library/config/standalone/intro.html#nginx-configuration-template

location ~ "^/assets/.+\.(woff|eot|svg|ttf|otf).*" {
    error_page 490 = @static_asset_fonts;
    error_page 491 = @dynamic_request;
    recursive_error_pages on;

    if (-f $request_filename) {
        return 490;
    }
    if (!-f $request_filename) {
        return 491;
    }
}

# Rails asset pipeline support.
location ~ "^/assets/.+-([0-9a-f]{32}|[0-9a-f]{64})\..+" {
    error_page 490 = @static_asset;
    error_page 491 = @dynamic_request;
    recursive_error_pages on;

    if (-f $request_filename) {
        return 490;
    }
    if (!-f $request_filename) {
        return 491;
    }
}

location @static_asset {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header ETag "";
}

location @static_asset_fonts {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header ETag "";
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, HEAD, OPTIONS';
    add_header 'Access-Control-Allow-Headers' '*';
    add_header 'Access-Control-Max-Age' 3628800;
}

location @dynamic_request {
    passenger_enabled on;
}

### END your own configuration options ###

Измените Procfile, чтобы включить эту пользовательскую конфигурацию файл

web: bundle exec passenger start -p $PORT --max-pool-size 2 --nginx-config-template ./config/passenger_config.erb

Затем разверните ...

===

Если вы знаете лучшее решение, пожалуйста, оставьте в комментариях.

После реализации команда CURL дала следующий ответ:

curl -H "Origin: https://tidyme-staging.com.au" -I http://tidyme-staging.com.au/assets/31907B_4_0-588bd4e720d4008295dcfb85ef36b233ee0817d7fe23c76a3a543ebba8e7c85a.ttf

HTTP/1.1 200 OK
Connection: keep-alive
Server: nginx/1.10.0
Date: Wed, 03 Aug 2016 01:43:48 GMT
Content-Type: application/x-font-ttf
Content-Length: 316664
Last-Modified: Fri, 22 Jul 2016 03:31:57 GMT
Expires: Thu, 31 Dec 2037 23:55:55 GMT
Cache-Control: max-age=315360000
Cache-Control: public
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD, OPTIONS
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 3628800
Accept-Ranges: bytes
Via: 1.1 vegur
8
ответ дан migu 2 February 2019 в 09:53
поделиться

У меня была та же проблема, и мне удалось ее решить.

Вы правильно сказали Cloudfront разрешить эти заголовки, но вы не добавили эти заголовки туда, где Cloudfront получает шрифт. Да, ваши исходные заголовки разрешены, но Heroku все равно не отправляет эти заголовки со шрифтом.

Чтобы это исправить, вам нужно добавить правильные заголовки CORS к шрифту на Heroku. К счастью, это довольно легко.

Сначала добавьте камень rack/cors в ваш проект. https://github.com/cyu/rack-cors

Затем настройте сервер Rack для загрузки и настройки CORS для любых ресурсов, которые он обслуживает. Добавьте следующее после предварительной загрузки приложения в config.ru

require 'rack/cors'
use Rack::Cors do
  allow do
    origins '*'

    resource '/cors',
      :headers => :any,
      :methods => [:post],
      :credentials => true,
      :max_age => 0

    resource '*',
      :headers => :any,
      :methods => [:get, :post, :delete, :put, :patch, :options, :head],
      :max_age => 0
    end
  end

. Это устанавливает любые ресурсы, возвращаемые из Heroku, для применения соответствующих заголовков CORS. Вы можете ограничить применение заголовков в зависимости от вашего файла и требований безопасности.

После развертывания перейдите в Cloudfront и начните аннулирование всего, что ранее давало вам ошибку разрешения CORS. Теперь, когда Cloudfront загружает свежую копию из Heroku, у него будут правильные заголовки, и Cloudfront передаст эти заголовки клиенту, как ранее было настроено с вашими Origin разрешениями.

Чтобы убедиться, что вы обслуживаете правильные заголовки со своего сервера, вы можете использовать следующую команду curl для проверки ваших заголовков: curl -I -s -X GET -H "Origin: www.yoursite.com" http://www.yoursite.dev:5000/assets/fonts/myfont.svg

Вы должны увидеть возвращенные следующие заголовки:

Access-Control-Allow-Origin: www.yoursite.com
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS, HEAD
Access-Control-Max-Age: 0
Access-Control-Allow-Credentials: true
2
ответ дан Joe Burns 2 February 2019 в 09:53
поделиться

Вот репозиторий, демонстрирующий использование пользовательского шрифта с Rails 5.2, который работает на Heroku. Это идет дальше и оптимизирует обслуживание шрифтов, чтобы быть максимально быстрым в соответствии с https://www.webpagetest.org/

https://github.com/nzoschke / edgecors

Asset Pipeline и SCSS

  • Поместить шрифты в app/assets/fonts
  • Поместить объявление @font-face в файл scss и использовать font-url помощник

Из app/assets/stylesheets/welcome.scss:

@font-face {
  font-family: 'Inconsolata';
  src: font-url('Inconsolata-Regular.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

body {
  font-family: "Inconsolata";
  font-weight: bold;
}

Служить из CDN с помощью CORS

Я использую CloudFront, добавленный с Heroku Edge addon .

Если вы используете свой собственный CloudFront, не забудьте настроить его так, чтобы он перенаправлял заголовок браузера Origin на исходный сервер.

Сначала настройте префикс CDN и заголовки Cache-Control по умолчанию в production.rb:

Rails.application.configure do
  # e.g. https://d1unsc88mkka3m.cloudfront.net
  config.action_controller.asset_host = ENV["EDGE_URL"]

  config.public_file_server.headers = {
    'Cache-Control' => 'public, max-age=31536000'
  }
end

Если вы попытаетесь получить доступ к шрифту с URL-адреса herokuapp.com на URL-адрес CDN, вы получите Ошибка CORS в вашем браузере:

Доступ к шрифту в ' https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf ' from origin ' https://edgecors.herokuapp.com 'заблокировано политикой CORS: в запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin». edgecors.herokuapp.com/ GET https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf net :: ERR_FAILED

Поэтому настройте CORS, чтобы разрешить доступ к шрифт от Heroku к URL CDN:

module EdgeCors
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    config.middleware.insert_after ActionDispatch::Static, Rack::Deflater

    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins %w[
          http://edgecors.herokuapp.com
          https://edgecors.herokuapp.com
        ]
        resource "*", headers: :any, methods: [:get, :post, :options]
      end
    end
  end
end

Служит gzip Font Asset

Конвейер ресурсов создает файл .ttf.gz, но не обслуживает его. Этот патч обезьяны заменяет белый список gzip конвейера ресурсов на черный список:

require 'action_dispatch/middleware/static'

ActionDispatch::FileHandler.class_eval do
  private

    def gzip_file_path(path)
      return false if ['image/png', 'image/jpeg', 'image/gif'].include? content_type(path)
      gzip_path = "#{path}.gz"
      if File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)))
        gzip_path
      else
        false
      end
    end
end

Конечным результатом является файл нестандартного шрифта в app/assets/fonts, который подается из долгоживущего кеша CloudFront.

0
ответ дан Noah Zoschke 2 February 2019 в 09:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: