我有通过快递设置cookie的问题。我正在使用Este.js dev stack
,我尝试在API auth /login
路由中设置Cookie。以下是我在/api/v1/auth/login
路径
res.cookie('token', jwt.token, {expires: new Date(Date.now() + 9999999)});
res.status(200).send({user, token: jwt.token});
在src/server/main.js
我已将cookie-parser
注册为第一个中间件
app.use(cookieParser());
/api/v1/auth/login
路由的响应标头包含
Set-Cookie:token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ..
但Cookie未保存在浏览器中(document.cookie
为空,发布工具中的Resources - Cookies
标签为空):(
修改
我发现,当我在/api/v1/auth/login
(没有通话res.send
或res.json
)
res.cookie('token', jwt.token, {expires: new Date(Date.now() + 9999999), httpOnly: false});
next();
然后设置了Cookie 并且响应标头设置了X-Powered-By:Este.js
...这会在expres frontend rendering part中设置esteMiddleware
。
当我使用res.send
res.cookie('token', jwt.token, {expires: new Date(Date.now() + 9999999), httpOnly: false}).send({user, token: jwt.token});`
next();
然后我得到错误Can't set headers after they are sent.
,因为使用了send
方法,所以前端渲染会抛出此错误。
但我必须从API发送数据,那么我该如何处理呢?
请帮帮我一下吗?谢谢!
答案 0 :(得分:26)
我有同样的问题。服务器响应带有cookie集:
Set-Cookie:my_cookie=HelloWorld; Path=/; Expires=Wed, 15 Mar 2017 15:59:59 GMT
但是浏览器没有保存cookie。
这就是我解决它的方法。
我在客户端代码中使用fetch
。如果您未在credentials: 'include'
选项中指定fetch
,则虽然服务器响应设置了Cookie,但Cookie既不会发送到服务器也不会被浏览器保存。
示例:
var headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
return fetch('/your/server_endpoint', {
method: 'POST',
mode: 'same-origin',
redirect: 'follow',
credentials: 'include', // Don't forget to specify this if you need cookies
headers: headers,
body: JSON.stringify({
first_name: 'John',
last_name: 'Doe'
})
})
希望它对某人有帮助。
答案 1 :(得分:4)
为此苦苦挣扎了3个小时,终于意识到,即使我只收到Cookie,我也应该将axios
设置为withCredentials
。
true
答案 2 :(得分:3)
我使用快递4和节点7.4和角度,我有同样的问题,我帮助这个:
a)服务器端:在文件app.js中,我给所有响应提供标题,如:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
这必须在所有路由器之前 我看到很多添加了这个标题:
res.header("Access-Control-Allow-Headers","*");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
但我不需要那个,
b)当你定义cookie你需要添加httpOnly:false,如:
res.cookie( key, value,{ maxAge: 1000 * 60 * 10, httpOnly: false });
c)客户端:在发送ajax时你需要添加:" withCredentials:true,"像:
$http({
method: 'POST',
url: 'url,
withCredentials: true,
data : {}
}).then(function(response){
// code
}, function (response) {
// code
});
祝你好运。
答案 3 :(得分:2)
有一些问题:
httpOnly : false
明确设置的Cookie将不可通过浏览器中的document.cookie
访问。它仍将与HTTP请求一起发送,如果您检查浏览器的开发工具,您很可能会在那里找到cookie(在Chrome中,它们可以在开发工具的 Resources 标签中找到); next()
只应在您希望推迟向应用程序的其他部分发送回复时使用,而您的代码判断 - 不是您想要的。所以,在我看来,这应该可以解决你的问题:
res.cookie('token', jwt.token, {
expires : new Date(Date.now() + 9999999),
httpOnly : false
});
res.status(200).send({ user, token: jwt.token });
作为旁注:httpOnly
默认为true
(防止恶意XSS脚本访问会话cookie等)是有原因的。如果您没有充分的理由通过客户端JS访问cookie,请不要将其设置为false
。
答案 4 :(得分:1)
仔细检查您的cookie的大小。
对我来说,我生成身份验证令牌以存储在cookie中的方式,导致cookie的大小随随后的登录尝试而增加,最终导致浏览器未设置cookie,因为它太大了。
答案 5 :(得分:1)
在cookie中将“ httpOnly”设置为true是没有问题的。
我正在对请求使用“ request-promise”,客户端是“ React”应用程序,但是技术并不重要。该请求是:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.binary_location = '/path/to/chrome'
driver = webdriver.Chrome(options=options, executable_path='/path/to/chromedriver')
driver.get('http://google.com/')
node.js(快速)服务器上的响应是:
var options = {
uri: 'http://localhost:4000/some-route',
method: 'POST',
withCredentials: true
}
request(options)
.then(function (response) {
console.log(response)
})
.catch(function (err) {
console.log(err)
});
客户端发出请求,服务器设置cookie,浏览器(客户端)接收它(您可以在“开发工具”的“应用程序”选项卡中看到它),然后我再次向服务器和cookie启动请求位于请求:“ req.headers.cookie”中,因此服务器可以进行访问以进行验证。
答案 6 :(得分:1)
我对跨源请求有同样的问题,这是我如何解决的。您需要专门告诉浏览器允许凭据。使用axios,您可以指定它以允许在每个请求上使用凭据,例如
axios.defaults.withCredentials = true
但是,这将被CORS政策阻止,您需要在api上指定凭据为真
const corsOptions = {
credentials: true,
///..other options
};
app.use(cors(corsOptions));
更新:这仅适用于本地主机 有关生产环境中问题的详细答案,请参见我的答案here
答案 7 :(得分:1)
我在 Angular 应用程序中遇到了同样的问题。尽管我使用过,但浏览器中并未设置 cookie
res.cookie("auth", token, {
httpOnly: true,
sameSite: true,
signed: true,
maxAge: 24 * 60 * 60 * 1000,
});
为了解决这个问题,我在服务器端的app.use(cors({ origin:true, credentials:true }));
文件中添加了app.js
在我的 Angular 客户端的订单服务中,我添加了 {withCredentials: true}
作为第二个参数,当 http 方法被调用时,就像下面的代码
getMyOrders() {
return this.http
.get<IOrderResponse[]>(this.SERVER_URL + '/orders/user/my-orders', {withCredentials: true})
.toPromise();}
希望对大家有所帮助。
答案 8 :(得分:0)
app.post('/api/user/login',(req,res)=>{
User.findOne({'email':req.body.email},(err,user)=>{
if(!user) res.json({message: 'Auth failed, user not found'})
user.comparePassword(req.body.password,(err,isMatch)=>{
if(err) throw err;
if(!isMatch) return res.status(400).json({
message:'Wrong password'
});
user.generateToken((err,user)=>{
if(err) return res.status(400).send(err);
res.cookie('auth',user.token).send('ok')
})
})
})
});
服务器响应正常,但cookie未存储在浏览器中
在chrome中添加Postman Interceptor Extension,使邮递员可以将cookie存储在浏览器中并重新使用请求。
答案 9 :(得分:0)
我也遇到了同样的问题。
代码在两个地方发生了变化:
const apiData = await fetch("http://localhost:5000/user/login",
{
method: "POST",
body: JSON.stringify(this.state),
credentials: "include", // added this part
headers: {
"Content-Type": "application/json",
},
})
const corsOptions = {
origin: true, //included origin as true
credentials: true, //included credentials as true
};
app.use(cors(corsOptions));
答案 10 :(得分:-1)
主要功能之一是正确设置标题。
对于nginx:
add-header Access-Control-Allow-Origin''domain.com';
add_header'Access-Control-Allow-Credentials''true';
将此添加到您的Web服务器。
然后使用如下形式的cookie:
"cookie": {
"secure": true,
"path": "/",
"httpOnly": true,
"hostOnly": true,
"sameSite": false,
"domain" : "domain.com"
}
从express获取cookie的最佳方法是使用cookie解析器。
答案 11 :(得分:-1)
如果客户端和服务器位于不同的域,则无法设置Cookie。可以使用不同的子域,但是不能使用不同的域和端口。
如果使用Angular作为前端,您可以将所有请求发送到与Angular应用程序相同的域(因此该应用程序会将所有API请求发送给自己),然后在每个HTTP API请求URL中粘贴/ api /-通常已配置在您的environment.ts文件中:
export const environment = {
production: false,
httpPhp: 'http://localhost:4200/api'
}
然后所有HTTP请求将使用environment.httpPhp + '/rest/of/path'
然后您可以通过如下创建proxy.conf.json来代理这些请求:
{
"/api/*": {
"target": "http://localhost:5200",
"secure": false,
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
}
}
然后将其添加到ng服务:
ng serve -o --proxy-config proxy.conf.json
然后重新启动应用程序,它应该可以正常工作,假设您的服务器实际上在HTTP响应标头中使用Set-Cookie。 (请注意,在diff域上,即使服务器配置正确,您也看不到Set-Cookie响应标头。)