要将 Turbolinks 5 与 Django 一起使用,如何在使用 redirect() 时自动包含 Turbolinks-Location header?
To use Turbolinks 5 with Django, how can I automate inclusion of the Turbolinks-Location header when using redirect()?
根据 "Following Redirects" (https://github.com/turbolinks/turbolinks#following-redirects) 的 Turbolinks 5 文档:
When you visit location /one
and the server redirects you to location
/two
, you expect the browser’s address bar to display the redirected
URL.
However, Turbolinks makes requests using XMLHttpRequest
, which
transparently follows redirects. There’s no way for Turbolinks to tell
whether a request resulted in a redirect without additional
cooperation from the server.
解决方法是:
send the Turbolinks-Location
header in response to a visit that was
redirected, and Turbolinks will replace the browser’s topmost history
entry with the value you provide.
The Turbolinks Rails engine performs this optimization automatically for non-GET XHR requests that redirect with the redirect_to
helper.
我对在我的 Django (1.11) 项目中使用 Turbolinks 非常感兴趣,我想知道是否有人可以为我指出正确的方向,告诉我如何创建新的 Django redirect() 函数或修改现有函数始终包含重定向功能所需的 Turbolinks-Location header。我绝对不想每次进行重定向时都手动设置此 header。
'Redirecting After a Form Submission' 部分中有一个类似的条目 (https://github.com/turbolinks/turbolinks#redirecting-after-a-form-submission) 如果您能帮助我理解如何实施,我将不胜感激:
If form submission results in a state change on the server that
affects cached pages, consider clearing Turbolinks’ cache with
Turbolinks.clearCache()
.
The Turbolinks Rails engine performs this optimization automatically
for non-GET XHR requests that redirect with the redirect_to
helper.
我确实看到 github 上有一个 "Drop-in turbolinks implementation for Django" 包,但这是从 turbolinks-classic 分叉出来的,源代码没有提到 Turbolinks-Location header所以我确定这不是我要找的。
您提到的 django 包实现了一个 middleware,负责添加 headers。似乎对于旧的 turbolinks,headers 有不同的名称。您可以编写自己的中间件来支持 turbolinks 5。
Instead of submitting forms normally, submit them with XHR.
您可以使用普通的 django 实现此目的。阅读 django CSRF doc - 他们详细解释了必要的内容。
一位 reddit 用户指向该项目 https://github.com/viewflow/django-material/blob/v2/material/middleware.py 中的一段代码后,我确实发现了如何完全按照我的尝试去做。
我将 TurbolinksMiddleware class 复制到我自己的 middleware.py 应用程序目录下,并将其列在我的 settings.py 中
# MIDDLEWARE CONFIGURATION
# --------------------------------------------------------------------------
MIDDLEWARE = [
.
.
.
'apps.middleware.TurbolinksMiddleware',
]
通过在我的 html 模板中包含 turbolinks.js 的常规安装步骤,一切似乎都正常工作。
这是 TurbolinksMiddleware class,以防它在上面的 link 中不可用:
class TurbolinksMiddleware(object):
"""
Send the `Turbolinks-Location` header in response to a visit that was redirected,
and Turbolinks will replace the browser’s topmost history entry .
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
is_turbolinks = request.META.get('HTTP_TURBOLINKS_REFERRER')
is_response_redirect = response.has_header('Location')
if is_turbolinks:
if is_response_redirect:
location = response['Location']
prev_location = request.session.pop('_turbolinks_redirect_to', None)
if prev_location is not None:
# relative subsequent redirect
if location.startswith('.'):
location = prev_location.split('?')[0] + location
request.session['_turbolinks_redirect_to'] = location
else:
if request.session.get('_turbolinks_redirect_to'):
location = request.session.pop('_turbolinks_redirect_to')
response['Turbolinks-Location'] = location
return response
根据 "Following Redirects" (https://github.com/turbolinks/turbolinks#following-redirects) 的 Turbolinks 5 文档:
When you visit location
/one
and the server redirects you to location/two
, you expect the browser’s address bar to display the redirected URL.However, Turbolinks makes requests using
XMLHttpRequest
, which transparently follows redirects. There’s no way for Turbolinks to tell whether a request resulted in a redirect without additional cooperation from the server.
解决方法是:
send the
Turbolinks-Location
header in response to a visit that was redirected, and Turbolinks will replace the browser’s topmost history entry with the value you provide.The Turbolinks Rails engine performs this optimization automatically for non-GET XHR requests that redirect with the
redirect_to
helper.
我对在我的 Django (1.11) 项目中使用 Turbolinks 非常感兴趣,我想知道是否有人可以为我指出正确的方向,告诉我如何创建新的 Django redirect() 函数或修改现有函数始终包含重定向功能所需的 Turbolinks-Location header。我绝对不想每次进行重定向时都手动设置此 header。
'Redirecting After a Form Submission' 部分中有一个类似的条目 (https://github.com/turbolinks/turbolinks#redirecting-after-a-form-submission) 如果您能帮助我理解如何实施,我将不胜感激:
If form submission results in a state change on the server that affects cached pages, consider clearing Turbolinks’ cache with
Turbolinks.clearCache()
.The Turbolinks Rails engine performs this optimization automatically for non-GET XHR requests that redirect with the
redirect_to
helper.
我确实看到 github 上有一个 "Drop-in turbolinks implementation for Django" 包,但这是从 turbolinks-classic 分叉出来的,源代码没有提到 Turbolinks-Location header所以我确定这不是我要找的。
您提到的 django 包实现了一个 middleware,负责添加 headers。似乎对于旧的 turbolinks,headers 有不同的名称。您可以编写自己的中间件来支持 turbolinks 5。
Instead of submitting forms normally, submit them with XHR.
您可以使用普通的 django 实现此目的。阅读 django CSRF doc - 他们详细解释了必要的内容。
一位 reddit 用户指向该项目 https://github.com/viewflow/django-material/blob/v2/material/middleware.py 中的一段代码后,我确实发现了如何完全按照我的尝试去做。
我将 TurbolinksMiddleware class 复制到我自己的 middleware.py 应用程序目录下,并将其列在我的 settings.py 中
# MIDDLEWARE CONFIGURATION
# --------------------------------------------------------------------------
MIDDLEWARE = [
.
.
.
'apps.middleware.TurbolinksMiddleware',
]
通过在我的 html 模板中包含 turbolinks.js 的常规安装步骤,一切似乎都正常工作。
这是 TurbolinksMiddleware class,以防它在上面的 link 中不可用:
class TurbolinksMiddleware(object):
"""
Send the `Turbolinks-Location` header in response to a visit that was redirected,
and Turbolinks will replace the browser’s topmost history entry .
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
is_turbolinks = request.META.get('HTTP_TURBOLINKS_REFERRER')
is_response_redirect = response.has_header('Location')
if is_turbolinks:
if is_response_redirect:
location = response['Location']
prev_location = request.session.pop('_turbolinks_redirect_to', None)
if prev_location is not None:
# relative subsequent redirect
if location.startswith('.'):
location = prev_location.split('?')[0] + location
request.session['_turbolinks_redirect_to'] = location
else:
if request.session.get('_turbolinks_redirect_to'):
location = request.session.pop('_turbolinks_redirect_to')
response['Turbolinks-Location'] = location
return response