无法从 fetch() 响应访问 cookie
Unable to access cookie from fetch() response
尽管这个问题在 SO 被问了好几次,比如:
或
Unable to set cookie in browser using request and express modules in NodeJS
None 的解决方案可以帮助我从 fetch()
响应
中获取 cookie
我的设置如下所示:
客户
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'same-origin',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
...
function handleSubmit(e) {
e.preventDefault();
registerNewUser({...values, avatarColor: generateAvatarColor()}).then(response => {
console.log(response.headers.get('Set-Cookie')); // null
console.log(response.headers.get('cookie')); //null
console.log(document.cookie); // empty string
console.log(response.headers); // empty headers obj
console.log(response); // response obj
}).then(() => setValues(initialState))
}
服务器
private setUpMiddleware() {
this.app.use(cookieParser());
this.app.use(bodyParser.urlencoded({extended: true}));
this.app.use(bodyParser.json());
this.app.use(cors({
credentials: true,
origin: 'http://localhost:4200',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
credentials: true
}));
this.app.use(express.static(joinDir('../web/build')));
}
...
this.app.post('/register', (request, response) => {
const { firstName, lastName, avatarColor, email, password }: User = request.body;
this.mongoDBClient.addUser({ firstName, lastName, avatarColor, email, password } as User)
.then(() => {
const token = CredentialHelper.JWTSign({email}, `${email}-${new Date()}`);
response.cookie('token', token, {httpOnly: true}).sendStatus(200); // tried also without httpOnly
})
.catch(() => response.status(400).send("User already registered."))
})
JavaScript fetch
方法不会发送客户端 cookie 并默默地忽略服务器端 Reference link in MDN 发送的 cookie,因此您可以使用 XMLHttpRequest
方法发送来自您客户端的请求。
我明白了。解决方案是将凭据设置为 'include'
,如下所示:
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
之后我需要在我的 cors 中间件中启用凭据:
this.app.use(cors({
credentials: true, // important part here
origin: 'http://localhost:4200',
optionsSuccessStatus: 200
})
然后最后我需要删除快速路由响应中的选项 {httpOnly: true}
:
response.cookie('token', '12345ssdfsd').sendStatus(200);
请记住,如果您像这样发送 cookie,它会直接设置为客户端 cookie。您现在可以看到 cookie 设置为:console.log(document.cookie)
.
但在实际环境中,您不想发送客户端可访问的 cookie。您通常应该使用 {httpOnly: true}
选项。
尽管这个问题在 SO 被问了好几次,比如:
或
Unable to set cookie in browser using request and express modules in NodeJS
None 的解决方案可以帮助我从 fetch()
响应
我的设置如下所示:
客户
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'same-origin',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
...
function handleSubmit(e) {
e.preventDefault();
registerNewUser({...values, avatarColor: generateAvatarColor()}).then(response => {
console.log(response.headers.get('Set-Cookie')); // null
console.log(response.headers.get('cookie')); //null
console.log(document.cookie); // empty string
console.log(response.headers); // empty headers obj
console.log(response); // response obj
}).then(() => setValues(initialState))
}
服务器
private setUpMiddleware() {
this.app.use(cookieParser());
this.app.use(bodyParser.urlencoded({extended: true}));
this.app.use(bodyParser.json());
this.app.use(cors({
credentials: true,
origin: 'http://localhost:4200',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
credentials: true
}));
this.app.use(express.static(joinDir('../web/build')));
}
...
this.app.post('/register', (request, response) => {
const { firstName, lastName, avatarColor, email, password }: User = request.body;
this.mongoDBClient.addUser({ firstName, lastName, avatarColor, email, password } as User)
.then(() => {
const token = CredentialHelper.JWTSign({email}, `${email}-${new Date()}`);
response.cookie('token', token, {httpOnly: true}).sendStatus(200); // tried also without httpOnly
})
.catch(() => response.status(400).send("User already registered."))
})
JavaScript fetch
方法不会发送客户端 cookie 并默默地忽略服务器端 Reference link in MDN 发送的 cookie,因此您可以使用 XMLHttpRequest
方法发送来自您客户端的请求。
我明白了。解决方案是将凭据设置为 'include'
,如下所示:
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
之后我需要在我的 cors 中间件中启用凭据:
this.app.use(cors({
credentials: true, // important part here
origin: 'http://localhost:4200',
optionsSuccessStatus: 200
})
然后最后我需要删除快速路由响应中的选项 {httpOnly: true}
:
response.cookie('token', '12345ssdfsd').sendStatus(200);
请记住,如果您像这样发送 cookie,它会直接设置为客户端 cookie。您现在可以看到 cookie 设置为:console.log(document.cookie)
.
但在实际环境中,您不想发送客户端可访问的 cookie。您通常应该使用 {httpOnly: true}
选项。