Javascript fetch возвращает 403 на сервере Apache
Боюсь с этой проблемой уже несколько дней, поэтому любая помощь будет очень признательна.
Мне удалось развернуть свой проект django на сервере Linux, и он работает нормально, за исключением отправки формы модели. На локальном сервере разработки все работает нормально, и вот рабочий процесс:
- Пользователь заполняет форму;
- Пользователь нажимает кнопку submit;
- Javascript перехватывает событие submit, отправляет запрос «POST» и получает ответ;
- На стороне сервера форма проверяется и, если все в порядке, отправляется письмо;
- HTML обновляется, чтобы добавить подтверждение регистрации формы;
Вот мой код:
home.html
<div class="col-lg-8 offset-lg-2">
<form method="POST" class="row mt-17" id="form" onsubmit="return false">
{% csrf_token %}
{% for field in form %}
{% if field.name not in "message" %}
<div class="col-12 col-sm-6">
<div class=form-group>
<label for={{field.name}} class="form-label">{{ field.label }}</label>
{{ field }}
</div>
</div>
{% else %}
<div class="col-12">
<div class=form-group>
<label for={{field.name}} class="form-label">{{ field.label }}</label>
{{ field }}
</div>
</div>
{% endif %}
{% endfor %}
<div class="form-group mb-0">
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</div>
</form>
</div>
main.js
const form = document.getElementById('form');
form.addEventListener("submit", submitHandler);
function submitHandler(e) {
e.preventDefault();
fetch("{% url 'messages-api' %}", {
credentials: "include",
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new FormData(form)
})
.then(response => response.json())
.then(data => {
alert("Got your message")
})
}
файлssl.conf
<Directory /home/admin/pinpoint/templates>
Require all granted
</Directory>
Alias /static /home/admin/pinpoint/static
<Directory /home/admin/pinpoint/static>
Require all granted
</Directory>
Alias /media /home/admin/pinpoint/media
<Directory /home/admin/pinpoint/media>
Require all granted
</Directory>
<Directory /home/admin/pinpoint/project>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIScriptAlias / /home/admin/pinpoint/project/wsgi.py
WSGIDaemonProcess pinpoint python-path=/home/admin/pinpoint python-home=/home/admin/pinpoint/venv
WSGIProcessGroup pinpoint
На сервере разработки при нажатии кнопки submit я получаю 403 (Forbidden) в консоли.
Поскольку версия для разработки работает нормально, я предполагаю, что это проблема с правами. Поэтому я дал apache права на владение и r+w в папке templates. Но проблема не исчезла.
Если я удаляю содержимое заголовков в команде fetch, форма регистрируется в базе данных, но через ~2 минуты я получаю Server Error(500).
Любая помощь/предложения приветствуются.
Проблема, скорее всего, связана с защитой CSRF и возможной неправильной обработкой данных формы. Я внес некоторые изменения и добавил дополнительные шаги, чтобы помочь решить проблему, как показано ниже:
// --- Updated form submission code ---
// main.js
const form = document.getElementById('form');
form.addEventListener("submit", submitHandler);
async function submitHandler(e) {
e.preventDefault();
// Get the CSRF token from the cookie
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
const formData = new FormData(form);
try {
const response = await fetch("{% url 'messages-api' %}", {
method: 'POST',
credentials: 'same-origin', // Important for CSRF
headers: {
'X-CSRFToken': csrftoken,
// Don't set Content-Type when using FormData
},
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
alert("Got your message");
} catch (error) {
console.error('Error:', error);
alert("There was an error submitting the form. Please try again.");
}
}
Ошибка 403 Forbidden возникает, когда CSRF-защита Django блокирует запрос, поэтому я обновил код, чтобы правильно включить CSRF-токен в заголовки запроса. Кроме того, использование credentials: ‘same-origin’
гарантирует, что куки будут отправлены вместе с запросом
‘Content-Type’
был удален, потому что при использовании FormData
браузер должен устанавливать его автоматически. Это позволяет браузеру правильно установить границу для многочастных данных формы.
Добавьте эти строки в конфигурацию Apache (ssl.conf) для обработки CORS и CSRF:
# Add to your ssl.conf
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Content-Type, X-CSRFToken"
Header set Access-Control-Allow-Methods "POST, GET, OPTIONS"
Убедитесь, что эти параметры Django правильно настроены в файле settings.py:
CSRF_COOKIE_SECURE = True # for HTTPS
CSRF_COOKIE_HTTPONLY = False # Allows JavaScript to read the cookie
CSRF_TRUSTED_ORIGINS = ['https://yourdomain.com'] # Add your domain
Проверьте эти разрешения на вашем сервере:
# Set appropriate permissions for Apache
sudo chown -R www-data:www-data /home/admin/pinpoint
sudo chmod -R 755 /home/admin/pinpoint
# Make sure media and static directories are writable
sudo chmod -R 775 /home/admin/pinpoint/media
sudo chmod -R 775 /home/admin/pinpoint/static
Чтобы выяснить, почему вы получаете ошибку 500 через 2 минуты:
Проверьте журналы ошибок Apache: /var/log/apache2/error.log
Проверьте журналы Django
Временно установите DEBUG = True
в settings.py, чтобы видеть подробные сообщения об ошибках
Добавьте правильную обработку ошибок в представление Django:
# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def your_view(request):
try:
# Your existing view logic here
return JsonResponse({'status': 'success'})
except Exception as e:
return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
Вы можете дополнительно проверить:
На вкладке Сеть инструментов разработчика браузера можно увидеть точный запрос/ответ
Просмотрите журналы Apache и Django на предмет конкретных сообщений об ошибках
.Проверьте, не настроены ли на вашем сервере какие-либо таймауты, которые могут быть причиной 2-минутной задержки
.
Надеюсь, это поможет!