簡體   English   中英

如何修復“類型錯誤:無法獲取”?

[英]How to fix 'TypeError: Failed to fetch'?

當我嘗試使用前端的fetch和后端的快速路由發送發布請求時,出現TypeError: Failed to fetch錯誤。

我能夠在數據庫中成功創建新用戶,但是當嘗試通過 fetch 承諾獲取新用戶數據時,就會拋出錯誤。

應用程序.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));
}

用戶.js

router.post('/users', function(req, res) {
   User.create(req.body)
   .then(function(user) {
      res.json({
         user: user
      })
   }
});

服務器.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");
});

我需要取回該用戶對象才能訪問其數據。

編輯:所以,我發現這個問題與如何在前端提交請求有關。 如果我創建以下函數,然后在加載app.js時調用它,則一切正常:

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();

但是,如果我嘗試通過表單中的onsubmitonclick 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));
});

問題是頁面正在重新加載,這使我無法及時獲取數據。 解決方案是簡單地在偵聽器中添加event.preventDefault()

應用程序.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));
});

問題是關於“TypeError 無法獲取”。 消息的措辭向其他答案中探討的網絡/服務器/CORS 類型問題的方向發送一個,但我發現有一個原因完全不同。

我遇到了這個問題,並在一段時間內從表面上看,特別困惑,因為它是由我的頁面在 Chrome 中而不是在 Firefox 中 POST 引起的。

直到我發現 chrome://net-internals/#events 並看到我的請求受到“delegate_blocked_by =“Opening Files””的影響后,我才終於有了線索。

我的請求是通過文件輸入元素發布從用戶計算機上傳的文件。 該文件恰好是在 Excel 中打開的文件。 雖然它在 Firefox 上發布得很好,但只有在關閉時才能在 Chrome 中發布。

您的 Web 應用程序的用戶需要被告知有關此潛在問題的信息,並且 Web 開發人員還應該意識到“TypeError 無法獲取”有時可能意味着“TypeError 未達到嘗試獲取的程度”

當涉及到 CORS 問題時,通常是因為服務器不知道如何正確處理它。 基本上,每次您在請求中包含像access-control-origin這樣的標頭時,它也會引發 OPTIONS 預檢請求,如果您的服務器不期望它會拋出錯誤,因為它期望只有 POST 請求。

換句話說 - 在沒有"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();
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM