传递给我的 Django 视图的请求中的 "cart" cookie 是空的,尽管它显示在浏览器存储中
My "cart" cookie in the request passed to my Django view is empty despite it showing in browser storage
我的网站上有一个商店页面(用带有 Passenger 服务器的 Django 编写),用户可以在其中将产品添加到他们的购物车中。购物车存储为 cookie。当他们从商店页面进入购物车页面时,购物车视图应该列出他们购物车中的所有商品(它从请求中的购物车 cookie 中获取)。当我在本地 运行 时,这很好用。但是,当我 运行 在生产中使用它时,它几乎总是说购物车是空的。如果我硬刷新页面,它只会正确列出购物车项目。
我已经向服务器添加了一些打印语句,我可以看到该页面的视图在产品中被调用了两次(它只在开发中被调用了一次)。第一次调用视图时,购物车 cookie 具有正确的值。然而,第二次调用它时,请求中的购物车 cookie 是空的 object {}。请求中的所有其他 cookie 看起来正常(session id、csrftoken 等)。非常奇怪的是,我可以在浏览器的开发人员面板中看到购物车 cookie 填充在请求的 header cookie 选项卡和存储选项卡中。
Django view/utility 函数:
def cart_view(request):
data = cart_data(request)
context = {
'items': data['items'],
'order': data['order'],
'cart_items': data['cart_items'],
}
return render(request, 'store/cart.html', context)
def cart_cookie(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
return cart
def cart_data(request):
cart = cart_cookie(request)
items = []
order = {'get_cart_total': 0, 'get_cart_items': 0, 'shipping': False}
cart_items = order['get_cart_items']
'''
Logic to parse the cart cookie
'''
return {
'items': items,
'order': order,
'cart_items': cart_items,
}
以下是商店页面上用于填充购物车的函数:
var updateBtns = document.getElementsByClassName('update-cart');
for (var i = 0; i < updateBtns.length; i++) {
updateBtns[i].addEventListener('click', function() {
var productId = this.dataset.product;
var action = this.dataset.action;
updateCartCookie(productId, action);
})
}
function updateCartCookie(productId, action) {
if (action == 'add') {
if (cart[productId] === undefined) {
cart[productId] = {'quantity':0};
}
cart[productId]['quantity'] += 1;
} else if (action == 'remove') {
cart[productId]['quantity'] -= 1;
if (cart[productId]['quantity'] <= 0) {
delete cart[productId];
}
}
document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/;SameSite=Strict;Secure;";
location.reload();
}
此代码在页面 header 中用于初始化 cookie。导航到购物车页面时未调用它。
<script type="text/javascript">
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++){
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1))
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken'); // this is just a string
var cart = JSON.parse(getCookie('cart')); // this is a json object, so we need to parse it
if (cart == undefined) {
cart = {};
document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/;SameSite=Strict;Secure;";
}
</script>
最后,这是商店和购物车页面的模板
#商店
{% block content %}
{% load static %}
<div class="container">
<h1 class="page-title">Store</h1>
<div class="row" style="margin-bottom: 20px">
{% for product in products %}
<div class="col-lg-4" style="margin-bottom: 20px">
<img class="thumbnail" src="{{product.imageURL}}">
<br>
<div class="box-element product">
<div>
<h4><strong>{{product.name}}</strong></h4>
<hr>
<p>
{{product.description}}
</p>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<h4>{{ product.price|floatformat:-2 }}</h4>
<button data-product={{product.id}} data-action="add" class="btn light update-cart">Add</button>
</div>
</div>
</div>
{% endfor %}
</div>
<div>
<a style="float: right; margin: 5px;" class="btn dark" href="{% url 'cart' %}">Cart</a>
</div>
</div>
{% endblock content %}
#购物车
{% block content %}
<div class="container">
<h1 class="page-title">Cart</h1>
<div class="">
<a class="btn button light" href="{% url 'store' %}">← Store</a>
<br>
<br>
{% if cart_items == 0 %}
<p style="text-align: center;">Your cart is empty.</p>
{% else %}
<div>
<div class="cart-row">
<div class="shrinking-flex-column-2-1"><strong>Item</strong></div>
<div class="static-flex-column-1"><strong>Price</strong></div>
<div class="static-flex-column-1"><strong>Quantity</strong></div>
<div class="static-flex-column-1"><strong>Total</strong></div>
</div>
{% for item in items %}
<div class="cart-row" style="align-items: center;">
<div class="shrinking-flex-column-2-1">{{item.product.name}}</div>
<div class="static-flex-column-1">${{item.product.price}}</div>
<div class="static-flex-column-1">
<p class="quantity">x{{item.quantity}}</p>
<div class="quantity">
<img class="chg-quantity update-cart" src="{% static 'store/images/arrow-up.png' %}" data-product={{item.product.id}} data-action="add" >
<img class="chg-quantity update-cart" src="{% static 'store/images/arrow-down.png' %}" data-product={{item.product.id}} data-action="remove" >
</div>
</div>
<div class="static-flex-column-1">${{item.get_total}}</div>
</div>
{% endfor %}
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<h5>Total Order Items: <strong>{{order.get_cart_items}}</strong></h5>
<h5>Total Order Amount: <strong>${{order.get_cart_total}}</strong></h5>
</div>
<a class="btn dark" role="button" href="{% url 'checkout' %}">Checkout</a>
</div>
</div>
{% endif %}
</div>
</div>
{% endblock content %}
这最终完全是一个缓存问题。添加 @never_cache 修饰到 cart/checkout 视图解决了问题。
我的网站上有一个商店页面(用带有 Passenger 服务器的 Django 编写),用户可以在其中将产品添加到他们的购物车中。购物车存储为 cookie。当他们从商店页面进入购物车页面时,购物车视图应该列出他们购物车中的所有商品(它从请求中的购物车 cookie 中获取)。当我在本地 运行 时,这很好用。但是,当我 运行 在生产中使用它时,它几乎总是说购物车是空的。如果我硬刷新页面,它只会正确列出购物车项目。
我已经向服务器添加了一些打印语句,我可以看到该页面的视图在产品中被调用了两次(它只在开发中被调用了一次)。第一次调用视图时,购物车 cookie 具有正确的值。然而,第二次调用它时,请求中的购物车 cookie 是空的 object {}。请求中的所有其他 cookie 看起来正常(session id、csrftoken 等)。非常奇怪的是,我可以在浏览器的开发人员面板中看到购物车 cookie 填充在请求的 header cookie 选项卡和存储选项卡中。
Django view/utility 函数:
def cart_view(request):
data = cart_data(request)
context = {
'items': data['items'],
'order': data['order'],
'cart_items': data['cart_items'],
}
return render(request, 'store/cart.html', context)
def cart_cookie(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
return cart
def cart_data(request):
cart = cart_cookie(request)
items = []
order = {'get_cart_total': 0, 'get_cart_items': 0, 'shipping': False}
cart_items = order['get_cart_items']
'''
Logic to parse the cart cookie
'''
return {
'items': items,
'order': order,
'cart_items': cart_items,
}
以下是商店页面上用于填充购物车的函数:
var updateBtns = document.getElementsByClassName('update-cart');
for (var i = 0; i < updateBtns.length; i++) {
updateBtns[i].addEventListener('click', function() {
var productId = this.dataset.product;
var action = this.dataset.action;
updateCartCookie(productId, action);
})
}
function updateCartCookie(productId, action) {
if (action == 'add') {
if (cart[productId] === undefined) {
cart[productId] = {'quantity':0};
}
cart[productId]['quantity'] += 1;
} else if (action == 'remove') {
cart[productId]['quantity'] -= 1;
if (cart[productId]['quantity'] <= 0) {
delete cart[productId];
}
}
document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/;SameSite=Strict;Secure;";
location.reload();
}
此代码在页面 header 中用于初始化 cookie。导航到购物车页面时未调用它。
<script type="text/javascript">
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++){
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1))
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken'); // this is just a string
var cart = JSON.parse(getCookie('cart')); // this is a json object, so we need to parse it
if (cart == undefined) {
cart = {};
document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/;SameSite=Strict;Secure;";
}
</script>
最后,这是商店和购物车页面的模板 #商店
{% block content %}
{% load static %}
<div class="container">
<h1 class="page-title">Store</h1>
<div class="row" style="margin-bottom: 20px">
{% for product in products %}
<div class="col-lg-4" style="margin-bottom: 20px">
<img class="thumbnail" src="{{product.imageURL}}">
<br>
<div class="box-element product">
<div>
<h4><strong>{{product.name}}</strong></h4>
<hr>
<p>
{{product.description}}
</p>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<h4>{{ product.price|floatformat:-2 }}</h4>
<button data-product={{product.id}} data-action="add" class="btn light update-cart">Add</button>
</div>
</div>
</div>
{% endfor %}
</div>
<div>
<a style="float: right; margin: 5px;" class="btn dark" href="{% url 'cart' %}">Cart</a>
</div>
</div>
{% endblock content %}
#购物车
{% block content %}
<div class="container">
<h1 class="page-title">Cart</h1>
<div class="">
<a class="btn button light" href="{% url 'store' %}">← Store</a>
<br>
<br>
{% if cart_items == 0 %}
<p style="text-align: center;">Your cart is empty.</p>
{% else %}
<div>
<div class="cart-row">
<div class="shrinking-flex-column-2-1"><strong>Item</strong></div>
<div class="static-flex-column-1"><strong>Price</strong></div>
<div class="static-flex-column-1"><strong>Quantity</strong></div>
<div class="static-flex-column-1"><strong>Total</strong></div>
</div>
{% for item in items %}
<div class="cart-row" style="align-items: center;">
<div class="shrinking-flex-column-2-1">{{item.product.name}}</div>
<div class="static-flex-column-1">${{item.product.price}}</div>
<div class="static-flex-column-1">
<p class="quantity">x{{item.quantity}}</p>
<div class="quantity">
<img class="chg-quantity update-cart" src="{% static 'store/images/arrow-up.png' %}" data-product={{item.product.id}} data-action="add" >
<img class="chg-quantity update-cart" src="{% static 'store/images/arrow-down.png' %}" data-product={{item.product.id}} data-action="remove" >
</div>
</div>
<div class="static-flex-column-1">${{item.get_total}}</div>
</div>
{% endfor %}
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<h5>Total Order Items: <strong>{{order.get_cart_items}}</strong></h5>
<h5>Total Order Amount: <strong>${{order.get_cart_total}}</strong></h5>
</div>
<a class="btn dark" role="button" href="{% url 'checkout' %}">Checkout</a>
</div>
</div>
{% endif %}
</div>
</div>
{% endblock content %}
这最终完全是一个缓存问题。添加 @never_cache 修饰到 cart/checkout 视图解决了问题。