如何处理此fetch()TypeError?

时间:2018-10-11 10:02:05

标签: javascript typeerror fetch-api

我正尝试将获取查询的响应状态打印到控制台(以便以后处理那些极端情况)。但是,唯一有效的console.log调用是“违背”功能中的调用。当帐户不在HIBP数据库中时,我没有收到任何错误,但是却收到“请求失败:TypeError:response.json不是json的函数”错误,而该帐户不在数据库中时。我究竟做错了什么?我从Google Web Dev文章中获得了错误处理代码。

function createNode(element) {
    return document.createElement(element);
}

function append(parent, el) {
    return parent.appendChild(el);
}

function status(response) {
    if (response.status >= 200 && response.status < 300) {
        return Promise.resolve(response)
        console.log('all is good');
    } else if (response.status == 404) {
        return Promise.resolve(response.statusText)
        console.log('no breaches');
    } else if (response.status == 400) {
        return Promise.resolve(response.statusText)
        console.log('bad req');
    } else {
        return Promise.reject(new Error(response.statusText))
    }
}

function json(response) {
    return response.json()
}

var account = document.getElementById('account'),
    results = document.getElementById('results');
account.addEventListener("keyup", keyupEvent);

function keyupEvent() {
    event.preventDefault();
    if (event.key === "Enter") {
        fetch('https://haveibeenpwned.com/api/v2/breachedaccount/' + account.value, {
                timeout: 1500,
                userAgent: 'test'
            })
            .then(status)
            .then(json)
            .then(function(breaches) {
                console.log('Status Code: ' + breaches.status);
                let span = createNode('span');
                return breaches.forEach(function(check) {
                    span.innerHTML = `${check.Name}<br/>`;
                    append(results, span)
                })

            }).catch(function(error) {
                console.log('Request failed:', error);
            });
    }
}

1 个答案:

答案 0 :(得分:2)

您的status函数返回(承诺)状态文本,表示响应为400或404。您使用fetch结果的诺言链无法解决这种可能性;假设它得到了响应对象。

您可能想拒绝400s或404s而不是解决问题,但是如果不能解决,则需要在then处理程序中分支,希望读取JSON。

您消耗违规的代码还会覆盖相同的span并重复附加;最终只会附上 last 违规信息。而且,append函数仅提供调用appendChild并没有提供任何有用的抽象。

如果API确实针对“无违规”(故障)返回404,那么我将摆脱createNodeappend,将status更改为此:

function status(response) {
    if (response.ok) {
        return response.json();
    } else if (response.status === 404) { // If the API *really* returns
        return [];                        // a 404 for "no breaches"
    } else {
        throw new Error(response.statusText);
    }
}

然后:

fetch('https://haveibeenpwned.com/api/v2/breachedaccount/' + account.value, {
        timeout: 1500,
        userAgent: 'test'
    })
    .then(status)
    .then(breaches => {
        // No `return` here, the chain isn't passed on and there
        // aren't any further resolution handlers
        breaches.forEach(check => {  // Or a for-of loop
            const span = document.createElement("span");
            span.innerHTML = `${check.Name}<br/>`;
            results.appendChild(span);
        });
    }).catch(error => {
        console.log('Request failed:', error);
    });

另外:您的status函数表明您没有意识到then(和catch创建新的诺言。如果您的status函数仅将用作then处理程序,则没有理由创建任何promise。它应该只是返回一个值(由then创建的承诺将使用该值进行解析)或引发错误(由then创建的承诺将由于该错误而拒绝):

// This is equivalent to your current `status` function (assuming it's always
// used as a `then` callback)
function status(response) {
    if (response.ok) { // if (response.status >= 200 && response.status < 300) {
        // all okay
        return response;
    } else if (response.status == 404) {
        // no breaches
        return response.statusText;
    } else if (response.status == 400) {
        // bad request
        return response.statusText;
    } else {
        throw new Error(response.statusText);
    }
}

(由于无法访问,我删除了每个分支中的{em> console.log之后的return。)