Ошибки отправки запроса на сервер через fetch()
На странице формы подключен скрипт js, который отправляет запрос на сервер при клике пользователя на одной из двух кнопок. Затем сервер возвращает ответ и браузер выводит сообщение с полученными данными.
js:
let element = document.querySelector('.button');
element.addEventListener('click', function(event) {
fetch("http://my_site/test", {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify({"key": event.target.value})
})
.then(response => response.json())
.then(data => alert(data));
});
серверный скрипт Laravel:
Route::post('/test', function (Request $request) {
$data = $request->input('key');
return json_encode($data);
});
В результате при клике по любой из кнопок в консоль выводятся следующие сообщения об ошибках:
POST http://my_site/test 419 (unknown status)
POST http://my_site/test 419 (unknown status)
Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Как я понял первые две ошибки говорят о проблеме с csrf-токеном. Попытался вылечить это добавив
в разметку тег <meta name="csrf-token" content="{{ csrf_token() }}">, но ошибка не ушла.
Две последние, как я прочитал говорят о том, что скрипт js отправляет не json, а html. Здесь я вообще не нашел, что можно предпринять.
Как устранить эти ошибки? Почему они задублированы? Спасибо!
Ответы (2 шт):
Ошибки возникают из-за того, что сервер возвращает ошибку 419, которая указывает на проблему с CSRF-токеном. Для решения этой проблемы необходимо добавить CSRF-токен в заголовок запроса. Для этого можно использовать следующий код:
let element = document.querySelector('.button');
let csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
element.addEventListener('click', function(event) {
fetch("http://my_site/test", {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({"key": event.target.value})
})
.then(response => response.json())
.then(data => alert(data));
});
Чтобы скрипт отправлял данные в формате JSON, необходимо убедиться, что сервер возвращает данные в формате JSON. В данном случае сервер возвращает HTML, что вызывает ошибку. Чтобы решить эту проблему, необходимо изменить серверный скрипт Laravel, чтобы он возвращал данные в формате JSON. Для этого можно использовать следующий код:
Route::post('/test', function (Request $request) {
$data = $request->input('key');
return response()->json($data);
});
Если эти изменения не помогут, то возможно, что проблема заключается в другом месте кода.
Отметьте, пожалуйста, мой предыдущий ответ как правильный.)
- Если сервер присылает ответ дважды, возможно, что проблема действительно связана с тем, что у вас две кнопки, слушающие одно и то же событие. Попробуйте добавить условие, чтобы запрос отправлялся только при клике на нужную кнопку:
let elements = document.querySelectorAll('.button');
let csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
elements.forEach(element => {
element.addEventListener('click', function(event) {
if (event.target.value === 'value') {
fetch("http://my_site/test", {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({"key": event.target.value})
})
.then(response => response.json())
.then(data => alert(data));
}
});
});
- Ошибка
Not allowed to load local resourceвозникает, когда вы пытаетесь загрузить файлы из локального диска напрямую в браузере. Для исправления этой ошибки необходимо запустить сервер на локальном хосте и загружать файлы через него. Вам необходимо изменить путь к файлу таким образом, чтобы он загружался через сервер. Например, если вы используете серверLaravel, то можно изменить путь следующим образом:
<link rel="stylesheet" href="{{ asset('assets/css/home.css') }}">
Если вы используете сборщик Vite, то можно использовать следующий код:
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
В этом случае, файл CSS будет загружаться через сервер, который запущен на локальном хосте.
<insert-here/>