#javascript #input #fetch-api #weather-api
Вопрос:
Я получаю TypeError: Failed to fetch
ошибку, когда пытаюсь отправить запрос post, используя fetch
интерфейс и экспресс-маршрут на серверной части.
Я могу успешно создать нового пользователя в базе данных, но при попытке получить эти новые пользовательские данные с помощью обещания выборки возникает ошибка.
app.js
function createNewUser() {
let formUsername = document.getElementById('signup-username').value;
let formEmail = document.getElementById('signup-email').value;
let formPassword = document.getElementById('signup-password').value;
let url = "/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer',
body: JSON.stringify(newUserData),
}).then(res => res.json())
.then(response => console.log('Success: ', JSON.stringify(response)))
.catch(error => console.error('Error: ', error));
}
users.js
router.post('/users', function(req, res) {
User.create(req.body)
.then(function(user) {
res.json({
user: user
})
}
});
server.js
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
const bodyParser = require('body-parser');
const bcrypt = require('bcryptjs');
const auth = require('./auth');
const router = require('./routes/routes.js');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(router);
app.use('/', express.static(path.join(__dirname, 'public')));
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE" // what matters here is that OPTIONS is present
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization", "Access-Control-Allow-Origin");
next();
});
app.listen(3000, function(){
console.log("Listening on port 3000");
});
I need to get that user object back in order to access its data.
Edit:
So, I’ve figured out that the issue has to do with how the request is submitted on the front-end. If I create the following function and then call it when app.js
is loaded, then everything works:
function createNewUserTest() {
let formUsername = 'dd';
let formEmail = 'd@d.com';
let formPassword = 'secrete';
let url = "/api/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUserData),
})
.then(res => res.json())
.then(response => console.log('Success: ', response))
.catch(error => console.error('Error: ', error));
}
createNewUserTest();
Но если я попытаюсь вызвать эту функцию либо onsubmit
через форму, либо onclick
через кнопку в html, либо если я использую прослушиватель событий (см. Ниже, который находится внутри app.js
), то я получу TypeError: Failed to fetch
ошибку:
let signupSubmitButton = document.getElementById('signup-submit');
signupSubmitButton.addEventListener('click', createNewUserTest);
Это еще больше сбивает меня с толку. От меня требуется использовать Vanilla JS, и мне нужно создать пользователя с помощью отправки формы, но я не уверен, что мне нужно изменить здесь.
Решение event.preventDefault()
снова сорвано. Это было все, что мне было нужно.
let signupForm = document.getElementById('signup-form');
signupForm.addEventListener('submit', function(event) {
event.preventDefault();
let formUsername = document.getElementById('signup-username').value;
let formEmail = document.getElementById('signup-email').value;
let formPassword = document.getElementById('signup-password').value;
let url = "/api/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUserData),
})
.then(res => res.json())
.then(response => console.log('Success: ', response))
.catch(error => console.error('Error: ', error));
});
Комментарии:
1. Вам не нужны CORS для одного и того же запроса источника… Я предполагаю, что именно поэтому он бросает, учитывая, что ваш сервер не будет отвечать заголовками CORS.
2. @PatrickRoberts Спасибо вам за ответ! Попробовал удалить
mode: 'cors'
, и я все еще получаю ту же ошибку.3. » Access-Control-Origin «, правильно названный Access-Control- Allow -Origin , является заголовком ответа , который должен быть отправлен с сервера клиенту, а не наоборот.
4. @Bergi Я добавил свой
server.js
код в свой первоначальный запрос. Я также удалил свойство CORS, а также удалил"Access-Control-Origin"
его из своегоheaders
объекта, но все равно получил ту же ошибку.5. Хм, обновленный код выглядит так, как будто он должен работать. На каком домене(доменах) вы пытаетесь запустить это? И что говорят разработчики о сетевых запросах?
Ответ №1:
Проблема заключалась в том, что страница перезагружалась, что мешало мне вернуть данные вовремя. Решение состояло в том, чтобы просто добавить event.preventDefault()
внутри слушателя.
app.js
let signupForm = document.getElementById('signup-form');
signupForm.addEventListener('submit', function(event) {
event.preventDefault();
let formUsername = document.getElementById('signup-username').value;
let formEmail = document.getElementById('signup-email').value;
let formPassword = document.getElementById('signup-password').value;
let url = "/api/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUserData),
})
.then(res => res.json())
.then(response => console.log('Success: ', response))
.catch(error => console.error('Error: ', error));
});
Комментарии:
1. Это именно то, что мне было нужно!
2. Очень трудную ошибку выявить! Спасибо!!
Ответ №2:
Вопрос заключается в том, что «Ошибка типа не удалось извлечь». Формулировка сообщения указывает на проблемы типа сеть/сервер/CORS, рассмотренные в других ответах, но есть одна причина, которую я обнаружил, которая совершенно иная.
У меня была эта проблема, и я некоторое время принимал ее за чистую монету, особенно озадаченный, потому что она была спровоцирована публикацией моей страницы в Chrome, но не в Firefox.
Только после того, как я обнаружил chrome://net-internals/#события и увидел, что мой запрос пострадал от «delegate_blocked_by = » Открытие файлов»», у меня наконец появилась подсказка.
Мой запрос состоял в публикации файла, загруженного с компьютера пользователя через элемент ввода файла. Этот файл оказался файлом, открытым в Excel. Хотя он был отлично размещен в Firefox, его можно было опубликовать в Chrome только после закрытия.
Пользователям вашего веб-приложения необходимо сообщить об этой потенциальной проблеме, и веб-разработчики также должны знать, что «Ошибка ввода не удалось извлечь» иногда может означать «Ошибка ввода не дошла до того, чтобы пытаться извлечь».
Ответ №3:
Когда дело доходит до проблем с CORS, это очень часто происходит из-за того, что сервер не знает, как правильно с этим справиться. По сути, каждый раз, когда вы добавляете заголовок, подобный access-control-origin
вашему запросу, он также инициирует предварительный запрос, и если ваш сервер не ожидает этого, он выдаст ошибку, потому что он ожидал запросов только для публикации.
Другими словами — попробуйте еще раз без этой "Access-Control-Origin": "*"
детали и посмотрите, работает ли она, или просто попробуйте исправить ее на сервере с помощью чего-то подобного:
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE" // what matters here is that OPTIONS is present
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
Комментарии:
1. Я добавил этот блок в свой server.js файл (из которого я запускаю
node server.js
), и даже добавлен"Access-Control-Allow-Origin
в последнийres.setHeader
метод, но все равно получаю ту же ошибку. Заставляет меня задуматься, не происходит ли что-то с моимserver.js
файлом, поэтому я добавляю это в свой первоначальный запрос.2. Теперь, когда я вижу, что вы обновили свой код с помощью server.js файл я думаю, что знаю, в чем проблема. Вы инициализировали все свои маршруты (приложение.использование(маршрутизатор)) перед той частью, когда вы устанавливаете заголовки. В узле запрос идет сверху вниз вашего файла, поэтому, хотя вы добавили эту часть setHeaders, уже слишком поздно, потому что запрос уже прошел по маршрутам без каких-либо заголовков, установленных на сервере. Попробуйте переместить свои маршруты после установки заголовков и посмотрите, сработает ли это.
3. Попробовал и это тоже, но безуспешно. Я думаю, что должно быть что-то в ответе от бэк-энда. Я отметил это в комментариях выше, но я могу выполнить успешный запрос GET к контроллеру, настроенному аналогичным образом, и я даже могу получить успешный ответ от запроса POST через почтальона. Firefox показывает
304 Not Modified
ошибку. Я немного покопался в этом, и я не уверен, почему это то, что я получаю. Также просто попробовал очистить кэш, но это тоже не помогло.