通过 p5 loadImage() 请求图像时,Safari 不会向 Express 发送 cookie

Safari doesn't send cookie to Express when requesting image via p5 loadImage()

背景

我在代理 后面设置了一个 Express.js 应用程序,让用户在被定向到网络应用程序之前先登录。此 应用程序无法在 Safari (macOS/iOS) 中提供一些图像,因为 Safari 没有发送回来自 loadImage() 方法的图像请求 的 cookie在我的 p5.js 代码中。 Chrome (macOS) 不会发生这种情况。

当我加载页面时,浏览器请求资源正常。但是来自我的应用程序 return 的请求是一个不同的 session,它没有登录,并被 Express 捕获:

// Request for the main page by the browser
Session {
  cookie:
   { path: '/',
     _expires: 2020-05-04T16:26:00.291Z,
     originalMaxAge: 259199998,
     httpOnly: true,
     secure: true },
  loggedin: true }

// Request for image assets by a script in my application
Session {
  cookie:
   { path: '/',
     _expires: 2020-05-04T16:26:00.618Z,
     originalMaxAge: 259200000,
     httpOnly: true,
     secure: true } }

来自 Safari 的 HTTP 请求

GET https://mydomain/app/img/svg/Water.svg HTTP/1.1
Host: mydomain
Origin: https://mydomain
Connection: keep-alive
If-None-Match: W/"5e6-171c689d240"
Accept: image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5
If-Modified-Since: Wed, 29 Apr 2020 15:24:13 GMT
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15
Referer: https://mydomain/app/
Accept-Language: en-us
Accept-Encoding: gzip, deflate, br

HTTP/1.1 302 Found
Date: Fri, 01 May 2020 06:50:07 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.3.17
X-Powered-By: Express
Location: /
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 23
Access-Control-Allow-Origin: *
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive

Found. Redirecting to /

快递应用

该应用程序设置在 HTTPS 代理后面,所以我将 Express Session object 设置为信任代理并将安全性设置为自动(设置为 false 不能解决问题):

app.set('trust proxy', 1)
app.use(session({
    secret: 'my-secret',
    resave: true,
    saveUninitialized: true,
    cookie: {
        secure: 'auto',
        maxAge: 259200000
    }
}));

当用户登录时,它被发送到 /auth 以检查数据库

app.post('/auth', function (request, response) {
    var user = request.body.user;
    var password = request.body.password;

    if (user && password) {
        connection.query('SELECT * FROM accounts WHERE user = ? AND password = ?', [user, password], function (error, results, fields) {
            if (results.length > 0) {

                request.session.loggedin = true;

                // If the user logs in successfully, then register the subdirectory
                app.use("/app", express.static(__dirname + '/private/'));

                // Then redirect
                response.redirect('/app');
            } else {
                response.send('Incorrect password!');
            }
            response.end();

            if (error) {
                console.log(error);
            }
        });
    } else {
        response.send('Please enter Username and Password!');
        response.end();
    }
});

他们在登录时被重定向到 /app

app.all('/app/*', function (request, response, next) {

    if (request.session.loggedin) {    
        next(); // allow the next route to run
    } else {
        // The request for images from my p5 script fails and these request redirect to "/"
        response.redirect("/");
    }
})

问题

我该怎么做才能确保 Safari 通过其请求传递 session cookie,以便 Express return 正确的资产?


编辑

包括调用loadImage()的函数。它嵌入在 ES6 class 中,该 ES6 class 为化学模拟中的粒子加载图像资源。此 class 必须成功解决承诺,以便其他更高阶 classes 可以设置正确的属性。

loadParticleImage() {

    return new Promise((resolve, reject) => {

        loadImage(this.imageUrl, (result) => {

            // Resolves the Promise with the result
            resolve(result);

        }, (reason) => {

            console.log(reason);
        });
    })
}

编辑#2

包含成功请求的headers直接到图片资源的URL:

GET https://mydomain/app/img/svg/Water.svg HTTP/1.1
Host: mydomain
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cookie: connect.sid=s%3A2frOCv41gcVRf1J4t5LlTcWkdZTdc8NT.8pD5eEHo6JBCHcpgqOgszKraD7AakvPsMK7w2bIHlr4
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15
Accept-Language: en-us
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

我建议使用 express's static middleware 来提供静态文件。有了这个,您将不需要任何会话来获取图像、js、css 等。此外,它还可以加速您的应用程序。您需要放置

app.use(express.static( ... )) 

如果您想要一些额外的性能,请在 app.use(session( ... )) 语句之前,因为如果您这样做,express 将不会尝试为静态文件创建会话。

source code for that loadImage() function is not setting the credentials option 中的 fetch() 调用控制 cookie 是否包含在请求中,因此它们不会随请求一起发送。

在提供图像之前您真的需要身份验证吗?如果没有,您可以重新安排在服务器中提供图像的方式,以便使用 express.static() 指向一个目录,该目录仅包含无需身份验证即可提供的资源,无需身份验证即可提供它们。如果他们确实需要进行身份验证,您可能需要修补 loadImage() 代码以使用 credentials: include 选项或以不同的方式加载图像。