Необработанный javascript, отображаемый на обратной кнопке

Недавно наша команда представила исходную проблему, в которой пользователю будет отображаться необработанный javascript при нажатии кнопки "Назад" браузера со страницы, на которой была какая-то рендеринг javascript (будь то Ajax, вкладки и т.д.). Чтобы воссоздать, мы выполнили следующие шаги:

  • Посетите индекс приложений для пользователей.
  • Нажмите кнопку на странице публикации задания управления.
  • Нажмите вкладку (используя драгоценный камень besttabs)
  • Нажмите кнопку "Назад" браузера.

Предыдущие шаги:

(function() {

  $(".job_applications").html("<li class=\"job_posting_application\">\n
    ...
    ...
    ...
    ...
  );

}).call(this);

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

В Rails Guides говорится о разделе Макеты и рендеринг, в частности, о типе MIME шаблона:

По умолчанию Rails будет обрабатывать результаты операции рендеринга с типом text/html содержимого MIME (или application/json, если вы используете опцию: json или application/xml для опции: xml.).

На основе значений Rails по умолчанию ожидается, что наше действие индекса контроллера отобразит наш шаблон index.html.slim. Однако при выполнении не удаленного вызова этой страницы (например, при непосредственном переходе на страницу в браузере) при отмене журналов сервера мы замечаем, что на самом деле он отображает index.js.coffee. Ниже приведено действие нашего контроллера и обратите внимание, что мы явно не отвечаем на форматы html или js, так как мы, вероятно, должны рассмотреть вышележащие функции на этой странице:

def index
  @company_id, @division_id, @job_posting_id = params[:company_id], params[:division_id], params[:job_posting_id]

  # API requests are made here to instantiate @job_posting, et al.,
  # but are not shown for brevity

  authorize! :manage, @job_posting

  @survey = @job_posting.survey
  @job_applications = @job_posting.job_applications(sort_column, sort_direction)
end

Однако, учитывая эту настройку, index.html.slim должен отображаться на основе значений по умолчанию Rails. При добавлении блока respond_to кажется, что кэширование все еще действует, и контроллер может не беспокоиться о наличии блока respond_to:

def index
  ...
  ...
  respond_to do |format|
    format.html
    format.js
  end
end

Даже если явно и хотя вонючий, говоря каждому формату для отображения другого шаблона, кажется, что шаблон js.coffee имеет приоритет над шаблоном html.slim:

def index
  ...
  ...
  respond_to do |format|
    format.html { render template: "users/job_posting_applications/index" }
    format.js { render template: "users/job_posting_applications/ajax" }
  end
end

В приведенном выше случае, непосредственно переходя к странице в браузере (другими словами, не делая удаленный вызов Ajax), журнал сервера будет отображать ajax.js.coffee, даже если по умолчанию Rails является html, если не указано иное.

Все это, как говорится, вот некоторые другие выводы:

Started GET "/users/companies/1/divisions/18/job_postings/349421/applications" for 127.0.0.1 at 2012-10-03 19:55:26 -0400
Processing by Users::JobPostingApplicationsController#index as JSON

(вы можете ссылаться на весь запрос, указанный выше в этом пасти)

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

Кроме того, при отладке значения request.format внутри этого действия он возвращает application/json.

Другой сценарий, который представлен, находится внутри другого контроллера (users/company_admin_metrics#index), который содержит только шаблон index.html.slim. При навигации по этой странице журнал сервера показывает, что он отображал users/company_admin_metrics/index.html.slim внутри layouts/users. Когда я создаю пустой шаблон js.coffee:

$ touch app/views/users/company_admin_metrics/index.js.coffee

и непосредственно перейдите к этой индексной странице, журнал сервера показывает, что он отобразил users/company_admin_metrics/index.js.coffee, что еще больше открывает потенциальную проблему, связанную с приоритетом препровождения шаблона.

Кто-нибудь сталкивался с подобной проблемой, которая может обеспечить потенциальное исправление для этого?

Наш стек

Ниже приводится список основных игроков в этот конкретный вопрос:

  • Rails 3.2.6
  • Coffee-Rails 3.2.1
  • Bettertabs 1.2.6

Этот запрос зависит от запросов на наш API публикации объявлений через клиентский жемчуг, который анализирует JSON и возвращает объект Ruby, но они не связаны с этим конкретным приложением таким образом, что это конфликтует и заставляет это приложение иметь контент тип application/json для такого запроса, как описано выше.

Ответ 1

Я думаю, вам нужно добавить расширение формата .js к URL-адресу в вашем запросе ajax.

Что, вероятно, происходит, так это то, что пользователь нажимает на действие index в /job_applications с запросом GET для html. Затем ajax нажимает один и тот же URL/действие, но запрашивает javascript. Когда пользователь нажимает кнопку "Назад", браузер не может определить разницу между ними, поэтому использует самую последнюю (ответ javascript).

Ответ 2

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

Как сказал Карбо, браузер может определить разницу между запросами html и js, поэтому при нажатии кнопки "Назад" он видит один и тот же URL-адрес и просто обслуживает кэшированные данные, которые происходят с кодом js. У меня была какая-то проблема, но с использованием javascript push state для изменения истории браузера для аякс-запросов. Самое простое решение, которое я нашел, это указать браузеру не кэшировать запрос. Так что, возвращаясь к предыдущей странице, ее нужно перезагрузить.

Вы можете отключить кеширование по всему миру: $.ajaxSetup({cache: false});

Или вы можете попробовать указать кеш-ложь для конкретного запроса ajax.

Ответ 3

В последнее время эта проблема появилась в Chrome с Rails 4.2.4. Представляется, что это известная и горячо обсуждаемая проблема. Наша команда решила его, добавив заголовок Vary к xhr запросам:

class ApplicationController < ActionController::Base
  after_action :set_vary_header

  private

  # Fix a bug/issue/by-design(?) of browsers that have a hard time understanding
  # what to do about our ajax search page. This header tells browsers to not cache
  # the current contents of the page because previously when someone filtered results,
  # went to the listing external site, then hit Back, they'd only see the last
  # ajax response snippet, not the full listings page for their search.
  #
  # Heated multi-year discussion on this issue in Chrome
  # https://code.google.com/p/chromium/issues/detail?id=94369
  #
  # And continued by the Rails team:
  # https://github.com/rails/jquery-ujs/issues/318
  # https://github.com/rails/jquery-rails/issues/121
  def set_vary_header
    if request.xhr?
      response.headers["Vary"] = "accept"
    end
  end
end