如何修复“类型错误:无法获取”?

Mic*_*nga 4 javascript fetch node.js express

我得到一个TypeError: Failed to fetch错误,当我试图发送使用POST请求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));
}
Run Code Online (Sandbox Code Playgroud)

用户.js

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

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

Run Code Online (Sandbox Code Playgroud)

我需要取回该用户对象才能访问其数据。

编辑: 所以,我发现这个问题与如何在前端提交请求有关。如果我创建以下函数,然后在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();
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试通过onsubmit表单或onclickhtml 中的按钮调用此函数,或者如果我使用事件侦听器(见下文,在 中app.js),则会TypeError: Failed to fetch出现错误:

let signupSubmitButton = document.getElementById('signup-submit');
signupSubmitButton.addEventListener('click', createNewUserTest);
Run Code Online (Sandbox Code Playgroud)

这对我来说更莫名其妙。我需要使用 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));
});
Run Code Online (Sandbox Code Playgroud)

Iai*_*Kay 9

问题是关于“TypeError 无法获取”。消息的措辞向网络/服务器/CORS 类型问题的方向发送了一个问题,正如其他答案中探讨的那样,但我发现有一个原因完全不同。

我遇到了这个问题,并在一段时间里只从表面上看待它,特别是困惑,因为它是由我在 Chrome 中发布的页面引起的,但在 Firefox 中却没有。

直到我发现 chrome://net-internals/#events 并看到我的请求受到 'delegate_blocked_by = "Opening Files"' 的影响后,我才终于有了线索。

我的请求是通过文件输入元素发布从用户计算机上传的文件。该文件恰好是在 Excel 中打开的文件。虽然它在 Firefox 中发布得很好,但只有在关闭时才能在 Chrome 中发布。

需要告知 Web 应用程序的用户有关此潜在问题的信息,并且 Web 开发人员还应该意识到“TypeError 无法获取”有时可能意味着“TypeError 未达到尝试获取的程度”


Mic*_*nga 6

问题是页面正在重新加载,这使我无法及时获取数据。解决方案是简单地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));
});
Run Code Online (Sandbox Code Playgroud)


小智 1

当涉及 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();
});
Run Code Online (Sandbox Code Playgroud)