У меня возникли проблемы с определением, почему именно мой идентификатор сеанса не установлен в моем API-интерфейсе expressjs.
Когда я запускаю Postman через запрос на публикацию /provision
:
const express = require("express");
require("express-async-errors");
const cors = require("cors");
const cookieSession = require("cookie-session");
const createTables = require("./queries/create-tables");
const keys = require("./keys");
const cleanup = require("./queries/cleanup");
const app = express();
app.set("trust proxy", "127.0.0.1");
app.use(
cors({
origin:
process.env.NODE_ENV === "production"
? ["<some-domain>", "<some-domain>"]
: ["http://localhost:3000"],
credentials: true,
})
);
app.use(express.json());
app.use(
cookieSession({
secure: process.env.NODE_ENV === "production",
keys: [keys.cookieKey],
sameSite: "Lax",
httpOnly: true,
domain: "<some-domain>",
})
);
app.use((req, res, next) => {
console.info("Session:", req.session);
if (!req.session) {
return next(new Error("Session is not set up properly"));
}
next();
});
app.post("/provision", require("./provision"));
app.post("/query", require("./query"));
app.post("/reset", require("./reset"));
Похоже, что логика предоставления.js успешно запущена:
const pool = require("./pool");
const createRole = require("./queries/create-role");
const createDb = require("./queries/create-db");
const { createId, validateId } = require("./queries/id");
module.exports = async (req, res) => {
let id = req.session.id;
if (!id) {
id = createId(8);
req.session.id = id;
}
validateId(id);
try {
await createRole(id);
await createDb(id);
res.send({ status: "ok" });
} catch (err) {
console.error(err);
throw new Error("Failed to provision db");
}
};
Но когда я запускаю запрос на публикацию на /query
со следующим запросом:
{
"query": "SELECT * FROM users WHERE id = 1"
}
Я получил:
{
"error": "Session ID is missing"
}
После проверки правильности промежуточного программного обеспечения сеанса обработка сеанса выглядит корректной, но почему идентификатор сеанса все еще не устанавливается?
Это код внутри query.js:
const createClient = require("./queries/create-client");
const { validateId } = require("./queries/id");
const dbExists = require("./queries/db-exists");
const touchLogin = require("./queries/touch-login");
module.exports = async (req, res) => {
const { id } = req.session;
console.info("Session:", id);
if (!id) {
return res.status(400).json({ error: "Session ID is missing" });
}
validateId(id);
if (!(await dbExists(id))) {
throw new Error("No database found. Reload this page.");
}
await touchLogin(id);
const client = await createClient(id);
try {
console.info("Query:", req.body.query);
const result = await client.query(req.body.query);
if (Array.isArray(result)) {
res.send(
result.map(({ rows, fields, command, rowCount }) => ({
command,
rows,
fields,
rowCount,
}))
);
} else {
res.send([
{
command: result.command,
rows: result.rows,
fields: result.fields,
rowCount: result.rowCount,
},
]);
}
} catch (err) {
console.error("Query Execution Error:", err);
res.status(500).json({ error: err.message });
} finally {
await client.end();
}
};
@WeDoTheBest4You, извините за поздний ответ. Я просто добавил это.
Привет, спасибо за обновление. Как мы знаем, сеанс cookie создает файл cookie при первом запросе и ссылается на него во всех последующих запросах. Поэтому файл cookie, созданный в первом запросе, должен прийти клиенту и сохраниться в разделе GoogleChrome/Инструменты разработчика/Приложение/Файлы cookie. Фактически мы можем видеть, что он хранится там после первого запроса. Можете ли вы посмотреть, произойдет ли это в этом случае? Вероятно, файл cookie может быть отклонен клиентом.
...Потенциальной причиной отклонения в соответствии с нынешней конфигурацией является заданное значение домена. Если домен домена: «<some-domain>», указанный здесь, не является субдоменом, то файл cookie будет рассматриваться как сторонний файл cookie и будет отклонен браузером. Если вы размещаете приложение и серверы API у двух разных хостинг-провайдеров, это может быть очевидной причиной.
...Следующие два документа будут полезны, если вы пробуете комплект двух разных поставщиков. devcenter.heroku.com/articles/cookies-and-herokuapp-com и devcenter.heroku.com/articles/custom-domains
@WeDoTheBest4You, когда я запускаю его в Postman, я не получаю никаких файлов cookie, полученных с сервера.
@WeDoTheBest4You, окей, я думаю, что мы можем чего-то добиться, поэтому на данный момент <some-domain>
— это вымышленное доменное имя, которое я надеюсь приобрести в будущем. Если это не сработает, что я могу использовать вместо этого?
Итак, я должен поблагодарить @WeDoTheBest4You за то, что помог мне найти решение. Итак, поскольку доменные имена, которые я использую, на самом деле еще не существуют, но у меня есть эти домены. Если домены не существуют, пользовательский агент не сможет разрешить доменные имена, что приведет к ошибкам при попытке подключения к этим серверам. В результате пользовательский агент даже не доходит до того момента, когда файлы cookie могут быть установлены или отправлены:
{
"query": "SELECT * FROM users WHERE id = 1"
}
Если у меня нет кристально ясного понимания этого, пожалуйста, кто-нибудь может отредактировать мое решение или комментарий, и я отредактирую его соответствующим образом.
Решением было реорганизовать мой файл index.js следующим образом:
const allowedOrigins =
process.env.NODE_ENV === "production"
? ["<some-domain>", "<some-other-domain>"]
: ["http://localhost:3000"];
app.set("trust proxy", process.env.NODE_ENV === "production" ? 1 : 0);
app.use(
cors({
origin: function (origin, callback) {
if (!origin) {
return callback(null, true);
}
if (allowedOrigins.indexOf(origin) === -1) {
const msg =
"The CORS policy for this site does not allow access from the specified origin";
return callback(new Error(msg), false);
}
return callback(null, true);
},
credentials: true,
})
);
// app.use(
// cors({
// origin:
// process.env.NODE_ENV === "production"
// ? ["<some-domain>", "<some-other-domain>"]
// : ["http://localhost:3000"],
// credentials: true,
// })
// );
app.use(express.json());
app.use(
cookieSession({
secure: process.env.NODE_ENV === "production",
keys: [keys.cookieKey],
sameSite: "Lax",
httpOnly: true,
domain: process.env.NODE_ENV === "production" ? "<some-domain>" : undefined,
})
);
И это сработало. Сейчас API все еще не работает, и теперь я получаю другую ошибку, но теперь эта ошибка устранена. Еще раз спасибо.
Привет! Причина отклонения файлов cookie пользовательскими агентами требует некоторой ясности. Это хорошо объяснено здесь, см. datatracker.ietf.org/doc/html/rfc6265#section-4.1.2.3. Следующая цитата посвящена этому:
... Пользовательский агент будет отклонять файлы cookie, если атрибут Домен не указывает область действия файла cookie, которая будет включать исходный сервер. Например, пользовательский агент примет файл cookie с атрибутом домена «example.com» или «foo.example.com» от foo.example.com, но пользовательский агент не примет файл cookie с атрибутом домена «example.com». «bar.example.com» или «baz.foo.example.com».
@WeDoTheBest4You, позвольте мне проверить, чтобы понять. Если домены не существуют, пользовательский агент не сможет разрешить имена доменов, что приведет к ошибкам при попытке подключения к этим серверам. В результате пользовательский агент даже не доходит до того момента, когда файлы cookie могут быть установлены или отправлены. Это правильно суммирует?
Привет. Спасибо за продолжение. Да, это правильно. Мы уверены, что мы передали и поняли суть вопроса в комментариях здесь. Чтобы подтвердить то же самое с помощью некоторых действий, я создал документ здесь — github.com/wedothebest4you/common. Пожалуйста, посмотрите, возможно ли это для вас, оно включает в себя тот же вопрос, но более обоснованный. Это общий репозиторий git, найдите в нем файл docx.
Привет! Было бы полезно, если бы вы включили точный сегмент кода в маршрут запроса, который вызывает эту ошибку: «ошибка»: «Идентификатор сеанса отсутствует».