使用 Fetch API 重新验证的 POST 请求不起作用

Posted

技术标签:

【中文标题】使用 Fetch API 重新验证的 POST 请求不起作用【英文标题】:POST request to restify with Fetch API not working 【发布时间】:2018-02-24 20:55:12 【问题描述】:

我在理解为什么 Fetch API 不允许我向我的 restify 服务器发送 POST 请求时遇到了一些重大问题。

我有一个基本的 restify 服务器,其路由接收 /login 上的 POST 请求。

如果我使用 Postman 或 HTTPRequester 进行测试,这条路由可以正常工作,但是当我使用 fetch API 在浏览器应用程序上测试它时,我收到以下错误(在 Chrome 中):

OPTIONS http://localhost:1337/login 405 (Method Not Allowed)

Fetch API cannot load http://localhost:1337/login. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 405. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

两个问题

    我在请求中专门使用了 POST 方法,为什么突然使用 OPTIONS? 我已经在我的服务器上设置了Access-Control-Allow-Origin: *

编辑:我使用restify v5.2.0

我的服务器应用

const restify = require('restify');
const app = restify.createServer(
    'name': 'API Token Test',
    'version': '1.0.0'
);

app.use(restify.plugins.acceptParser(app.acceptable));
app.use(restify.plugins.bodyParser());
app.use(restify.plugins.jsonp());

app.use((req, res, next) => 
	res.header('Access-Control-Allow-Origin', '*');
	res.header('Access-Control-Allow-Headers', 'X-Requested-With');
	return next();
);

app.post('/login', (req, res) => 
    db.execute('SELECT idusers, password FROM users WHERE username = ?', [req.body.username], (selError, rows) => 
        if (passwordHash.verify(req.body.password, rows[0].password)) 
            crypto.randomBytes(256, (err, buf) => 
                if (err) return res.status(500).end();
                else 
                    const token = buf.toString('hex');
                    db.execute('INSERT INTO accesstokens SET userid = ?, token = ?', [rows[0].idusers, token], (insError) => 
                        if (insError) return res.status(500).end();
                        else return res.send( "AccessToken": token );
                    );
                
            );
         else 
            res.status(401).end();
        
    );
);

app.listen(1337);

(我省略了与问题无关的 mysql 内容和加密/密码哈希 -requires)

还有我的客户端脚本

(() => 
    document.addEventListener('DOMContentLoaded', () => 
        const form = document.querySelector('.loginForm');

        form.onsubmit = () => 
            const data = JSON.stringify(
                'username': form.username.value,
                'password': form.password.value
            );

            let headers = new Headers();
            headers.set('Accept', 'application/json');
            headers.set('Content-Type', 'application/json');
            headers.set('Content-Length', data.length);


            fetch('http://localhost:1337/login', 
                'method': 'POST',
                'headers': headers,
                'mode': 'cors',
                'cache': 'default',
                'body': data
            )
                .then((result) => result.json())
                .then((data) => 
                    console.log(data);
                    localStorage.setItem('token', data);
                )
                .catch((err) => 
                    console.log(err);
                );

            return false;
        ;
    );
)();

【问题讨论】:

【参考方案1】:

似乎自 restify v5.x 以来所有 CORS 支持已移至 this module。

安装 restify-cors-middleware 并将以下内容添加到我的应用程序有效:

const corsMiddleware = require('restify-cors-middleware');
const cors = corsMiddleware(
    'origins': ['*']
);
app.pre(cors.preflight);
app.use(cors.actual);

【讨论】:

以上是关于使用 Fetch API 重新验证的 POST 请求不起作用的主要内容,如果未能解决你的问题,请参考以下文章

ReactJS 从 API fetch 中获取令牌字符串

javascript 使用fetch API的简单POST请求

使用 javascript fetch api 执行 POST 请求

使用 fetch api 调用带有 keepalive 的 POST 请求时,预检请求失败

使用 fetch 时 POST https://accounts.spotify.com/api/token 415 错误

将 jquery ajax POST 请求更改为 fetch api POST