后台返回401浏览器会发生什么

读http权威指南

Posted by BY on September 27, 2023

读Http权威指南时有这样一段描述:

如果服务器希望在为用户提供对站点的访问之前,先行登录,可以向浏览器回送一条 HTTP 响应代码 401 Login Required。然后,浏览器会显示一个登录对话框,并
用 Authorization 首部在下一条对服务器的请求中提供这些信息

实践一下现代浏览器会不会真的这样

后台使用Koa,前台直接写html,先使用jsonp,通过script标签来获取数据,返回401

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button class="target">测试</button>
    <script>
        var target = document.querySelector('.target');

        function callback(arg) {
            console.log(arg)
        }

        target.addEventListener('click', function () {
            let script = document.createElement('script')
            script.src = 'http://localhost:3000/'
            document.body.append(script)
        });
    </script>
</body>

</html>

app.js

const Koa = require('koa')
const app = new Koa()

app.use(async ctx => {
    ctx.code = 401
    ctx.body = `callback('hello world')`
})

app.listen(3000)

发现前端正常打印数据,浏览器并不会弹出登录框,如下

换用cors和xhr尝试一下

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button class="target">测试</button>
    <script>
        function get(url) {
            return new Promise(function (fulfil, reject) {
                var xhr = new XMLHttpRequest();

                xhr.open('GET', url);

                xhr.onload = function () {
                    fulfil(xhr.responseText);
                };

                xhr.onerror = reject;

                xhr.send();
            });
        }

        var target = document.querySelector('.target');

        target.addEventListener('click', function () {
            get('http://localhost:3000/')
                .then(function (data) {
                    target.innerHTML = data;
                });
        });

    </script>
</body>

</html>

app.js

const Koa = require('koa')
const app = new Koa()

app.use(async ctx => {
    ctx.status = 401
    ctx.set('Access-Control-Allow-Origin', '*');
    ctx.set('Access-Control-Allow-Credentials', 'true');
    ctx.body = `hello world`
})

app.listen(3000)

发现后台虽然返回了401,但是chrome并没有弹出要求登录的弹窗

综上,可以得出结论:

在通过jsonp和xhr或者接口json数据时,只返回401,chrome浏览器是不会主动弹出要求登录的弹窗的

在网络上查阅资料后知道,除了http状态码为401之外,后台还必须在请求头设置WWW-Authenticate响应头部,如下:

ctx.set("WWW-Authenticate", `Basic realm="oauth2/client"`)

可以看到浏览器会弹出登录弹窗,如下: