Необработанный 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