【问题标题】:Safari doesn't send cookie to Express when requesting image via p5 loadImage()通过 p5 loadImage() 请求图像时,Safari 不会向 Express 发送 cookie
【发布时间】:2020-05-02 02:56:21
【问题描述】:

背景

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

当我加载页面时,浏览器会很好地请求资源。但是来自我的应用程序的请求会返回一个不同的会话,该会话未登录,并被 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 对象设置为信任代理并将安全设置为自动(设置为 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 通过其请求传递会话 cookie,以便 Express 将返回正确的资产?


编辑

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

loadParticleImage() {

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

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

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

        }, (reason) => {

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

编辑#2

将成功请求的标头直接包含到图像资产的 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

【问题讨论】:

  • 请出示loadImage()客户端代码。
  • 您已显示失败请求的标头。请同时显示正确请求的标头。
  • 嗨@jfriend00 我添加了特定的函数调用。它非常简单,返回一个解析 loadImage() 的结果的承诺,以便其他类等待访问属性,直到它们被定义。
  • @CoderFF 当我直接在浏览器中访问文件时,我在编辑#2 中包含了成功的标题
  • 我在询问导致 GET 请求从您仍未显示的浏览器发送的实际代码。我想看看实际的 Ajax 调用。你仍然没有显示出来。

标签: express safari p5.js express-session


【解决方案1】:

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

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

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

【讨论】:

  • 我最初试图这样做,但我现在意识到我正在为应用程序的根提供服务(使登录会话没有意义)。我没有想到将子文件夹选择性地提供为静态的。这解决了问题。
  • 我删除了所有的 cmets。
【解决方案2】:

source code 中针对 loadImage() 函数的 fetch() 调用未设置控制 cookie 是否包含在请求中的 the credentials option,因此它们不会随请求一起发送。

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

【讨论】:

  • 嗯,有道理。我会向 p5 团队指出这一点,因为我确信其他人在 Safari 上也会遇到同样的问题。
  • @dfd0226 - 我很好奇,深入了解这里实际发生的事情的答案不是您最有帮助的答案吗?
猜你喜欢
  • 2020-07-07
  • 1970-01-01
  • 1970-01-01
  • 2019-11-06
  • 1970-01-01
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
相关资源
最近更新 更多