2017-03-10 84 views
0

我正在使用Express.js服务器。随着cookie-parser我开这个端点fetch()无法设置从服务器接收的cookie?

app.get("/s", (req,res) => { 
    res.cookie("bsaSession", req.session.id) 
    res.send("set cookie ok") 
}) 

当我手动使用浏览器来http://localhost:5555/s在那里我有运行浏览器的调试控制台的网站显示,该cookie已经被应用。

enter image description here

但是当我使用fetch API做等价的,它不设置cookie。

async trySetCookie() 
    { 
    await fetch("http://localhost:5555/s",{ 
     method: 'GET', 
     credentials: 'same-origin' 
    }) 
    } 

为什么?

+1

“它不设置cookie”---你怎么知道的?浏览器是否发送了请求头中的cookie? – zerkms

+0

我查看了Safari调试控制台>存储> Cookies。当我点击调用'trySetCookie()'的按钮时,列表不会改变。但是,当我直接进入该页面时,该列表立即添加了新的Cookie。 – 5argon

+1

那么,你在响应头文件中看到了“Set-Cookie”吗?该脚本是否在同一个端口上运行? – zerkms

回答

1

我找到了解决方案。这个问题的核心是我的按钮触发fetch是在http://localhost:3000/。该服务器是http://localhost:5555/(我是我自己的机器上模拟真实环境)

的问题是,这fetch通话

async trySetCookie() 
    { 
    await fetch("http://localhost:5555/s",{ 
     method: 'GET', 
     credentials: 'same-origin' 
    }) 
    } 

没有credentials,浏览器无法发送或通过fetchhttps://developer.mozilla.org/en-US/docs/Web/API/Request/credentials

接收cookies

credentials as same-origin我可以看到来自服务器的响应头Set-Cookie中的cookie,但没有任何内容存储在浏览器中。奇怪的是,无论服务器上的我的{httpOnly : true/false}设置如何,此响应始终都会在Cookie字符串后标记HttpOnly。在手动使用浏览器到页面执行GET请求的情况下,HttpOnly像往常一样受到尊重,并设置了Cookie。

因此,解决方案是将credentials设置为include以允许跨源cookie发送。

async trySetCookie() 
    { 
    await fetch("http://localhost:5555/s",{ 
     method: 'GET', 
     credentials: 'include' 
    }) 
    } 

此外,在服务器端,你需要手动允许特定的原产地与新标题:

app.get("/s", (req,res) => { 
    res.cookie("bsaSession", req.session.id, {httpOnly:false}) 
    res.header('Access-Control-Allow-Origin', 'http://localhost:3000') 
    res.header('Access-Control-Allow-Credentials','true' 
    res.send("set") 
}) 

不这样做会导致

XMLHttpRequest cannot load http://localhost:5555/s. Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.

但cookie将不管这个错误如何设置。仍然很高兴能够包含该标题来消除错误。

如果您使用cors中间件for Express它更容易。你可以使用这些选项

var corsOptions = { 
    origin: 'http://localhost:3000', 
    credentials: true 
} 

app.use(cors(corsOptions)) 

当然credentials: 'include'的,仍然是需要在客户端。