在 Roku 上请求后看不到任何 cookie
Not seeing any cookies after request on Roku
我有一个 Roku 应用程序,它会在播放视频时对后端服务进行多次异步调用。 可能其中一些呼叫可能同时发生。这些调用都依赖于 cookie 进行身份验证。
因为调用依赖于 cookie 进行身份验证,所以我需要使用单个 roUrlTransfer
对象。如果我为每个请求创建一个新的 roUrlTransfer
实例,它们将不会共享 cookie 缓存
但是因为两个调用可能同时发生,所以我不能使用单个 roUrlTransfer
对象。根据 Roku documentation:
Each roUrlTransfer object can perform only one asynchronous operation at one time. After starting an asynchronous operation, you cannot perform any other data transfer operations using that object until the asynchronous operation has completed, as indicated by receiving an roUrlEvent message whose GetSourceIdentity value matches the GetIdentity value of the roUrlTransfer.
为了解决这两个问题,我创建了一个包装器对象。我维护一个名为“cookieJar”的单例 roUrlTransfer
对象,然后根据请求启动一个新的 roUrlTransfer
实例:
' ********************************************************************
' ** URL class to streamline adding query parameters and making requests.
' ********************************************************************
Function Downloader() As Object
return {
Send: Downloader_Send
AsyncWait: Downloader_AsyncWait
}
End Function
Function CookieJar() As Object
if m.cookiejar = invalid
m.cookiejar = CreateObject("roUrlTransfer")
m.cookiejar.EnableCookies()
end if
return m.cookiejar
End Function
Function Downloader_Send(req={} As Object)
if req.url <> invalid
m.req = req
m.http = CreateObject("roUrlTransfer")
m.port = CreateObject("roMessagePort")
m.http.SetPort(m.port)
m.http.EnableEncodings(true)
' ParseURL is a helper function I wrote that just breaks a URL into
' its components: scheme, host, path, query, and fragment
m.url = ParseURL(req.url)
m.http.EnableCookies()
m.http.AddCookies(CookieJar().GetCookies(m.url.host, m.url.path))
m.http.SetUrl(req.url)
if req.method <> invalid
m.http.SetRequest(req.method)
else
m.http.SetRequest("GET")
end if
if req.timeout <> invalid
m.timeout = req.timeout
else
m.timeout = 5000
end if
data = {}
if req.body <> invalid
if m.http.AsyncPostFromString(FormatJSON(req.body))
data = m.AsyncWait()
end if
else
if m.http.AsyncGetToString()
data = m.AsyncWait()
end if
end if
end if
return data
End Function
Function Downloader_AsyncWait() As Dynamic
event = wait(m.timeout, m.port)
if type(event) = "roUrlEvent"
print "Headers:"
print event.GetResponseHeaders()
print "Adding cookies to cookie jar:"
print m.http.GetCookies(m.url.host, m.url.path)
print m.http.GetCookies("", "/")
CookieJar().AddCookies(m.http.GetCookies(m.url.host, m.url.path))
return {
statusCode: event.GetResponseCode()
error: event.getFailureReason()
body: event.GetString()
headers: event.GetResponseHeaders()
}
else if event = invalid
m.http.AsyncCancel()
end if
return invalid
End Function
为了测试我的代码,我启动了一个非常简单的 ExpressJS 服务器,它除了设置一个 cookie 什么都不做:
var express = require("express");
var cookieParser = require("cookie-parser");
var app = express();
app.use(cookieParser());
app.get("/", function (req, res) {
res.cookie("key", "value", {
domain: "192.168.1.102:3333",
path: "/",
expire: Date.now() + 3600000
});
res.send("Done");
});
var server = app.listen(3333, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
});
然后在我的 Roku 应用程序中(在主屏幕上)我有以下内容:
httpClient = Downloader()
httpClient.Send({
' My local IP address
url: "http://192.168.1.102:3333"
})
当我在我的 Roku 上 运行 时,我在调试日志中看到以下内容:
Headers:
<Component: roAssociativeArray> =
{
connection: "keep-alive"
content-length: "13"
content-type: "text/html; charset=utf-8"
date: "Tue, 11 Aug 2020 17:29:52 GMT"
etag: "W/"d-w+Ote5otCKx40dtR446Vz7wX66U""
set-cookie: "key=value; Path=/"
x-powered-by: "Express"
}
Adding cookies to cookie jar:
<Component: roArray> =
[
]
<Component: roArray> =
[
]
m.http.GetCookies(m.url.host, m.url.path)
和 m.http.GetCookies("", "/")
均未返回任何 cookie。但是你可以清楚地看到header中的cookie!那为什么我不能访问它?
请注意,m.url.host
是 192.168.1.102:3333
,m.url.path
是
(空白),以防有助于理解任何内容...
在为此工作了一整天后,我发现 Roku 无法正确处理 cookie 域中的 ports。当 192.168.1.102:3333
提供 cookie 时,Roku 在内部将 cookie 标记为属于 192.168.1.102
(无端口)。
这有两个含义:
- 如果使用
...; domain=...;
属性提供 cookie,并且此域包含端口,Roku 将完全无法解析 set-cookie
header 并且不会提取任何 cookie
- 如果提供的 cookie 没有 此属性,那么 Roku 将解析
set-cookie
header,但是 GetCookies()
只会 return 如果未给定域 (""
) 或给定 port-less 域,则为 cookie。 GetCookies("192.168.1.102", "/")
return cookie 但 GetCookies("192.168.1.102:3333", "/")
没有
因为我的代码的目的是在多个 roUrlTransfer 实例之间共享 cookie,所以使用 GetCookies("", "/")
获取 all cookie 是可以接受的,所以我们将修改我们的back-end 从我们的 set-cookie
headers
中删除 ...; domain=...;
属性
我有一个 Roku 应用程序,它会在播放视频时对后端服务进行多次异步调用。 可能其中一些呼叫可能同时发生。这些调用都依赖于 cookie 进行身份验证。
因为调用依赖于 cookie 进行身份验证,所以我需要使用单个 roUrlTransfer
对象。如果我为每个请求创建一个新的 roUrlTransfer
实例,它们将不会共享 cookie 缓存
但是因为两个调用可能同时发生,所以我不能使用单个 roUrlTransfer
对象。根据 Roku documentation:
Each roUrlTransfer object can perform only one asynchronous operation at one time. After starting an asynchronous operation, you cannot perform any other data transfer operations using that object until the asynchronous operation has completed, as indicated by receiving an roUrlEvent message whose GetSourceIdentity value matches the GetIdentity value of the roUrlTransfer.
为了解决这两个问题,我创建了一个包装器对象。我维护一个名为“cookieJar”的单例 roUrlTransfer
对象,然后根据请求启动一个新的 roUrlTransfer
实例:
' ********************************************************************
' ** URL class to streamline adding query parameters and making requests.
' ********************************************************************
Function Downloader() As Object
return {
Send: Downloader_Send
AsyncWait: Downloader_AsyncWait
}
End Function
Function CookieJar() As Object
if m.cookiejar = invalid
m.cookiejar = CreateObject("roUrlTransfer")
m.cookiejar.EnableCookies()
end if
return m.cookiejar
End Function
Function Downloader_Send(req={} As Object)
if req.url <> invalid
m.req = req
m.http = CreateObject("roUrlTransfer")
m.port = CreateObject("roMessagePort")
m.http.SetPort(m.port)
m.http.EnableEncodings(true)
' ParseURL is a helper function I wrote that just breaks a URL into
' its components: scheme, host, path, query, and fragment
m.url = ParseURL(req.url)
m.http.EnableCookies()
m.http.AddCookies(CookieJar().GetCookies(m.url.host, m.url.path))
m.http.SetUrl(req.url)
if req.method <> invalid
m.http.SetRequest(req.method)
else
m.http.SetRequest("GET")
end if
if req.timeout <> invalid
m.timeout = req.timeout
else
m.timeout = 5000
end if
data = {}
if req.body <> invalid
if m.http.AsyncPostFromString(FormatJSON(req.body))
data = m.AsyncWait()
end if
else
if m.http.AsyncGetToString()
data = m.AsyncWait()
end if
end if
end if
return data
End Function
Function Downloader_AsyncWait() As Dynamic
event = wait(m.timeout, m.port)
if type(event) = "roUrlEvent"
print "Headers:"
print event.GetResponseHeaders()
print "Adding cookies to cookie jar:"
print m.http.GetCookies(m.url.host, m.url.path)
print m.http.GetCookies("", "/")
CookieJar().AddCookies(m.http.GetCookies(m.url.host, m.url.path))
return {
statusCode: event.GetResponseCode()
error: event.getFailureReason()
body: event.GetString()
headers: event.GetResponseHeaders()
}
else if event = invalid
m.http.AsyncCancel()
end if
return invalid
End Function
为了测试我的代码,我启动了一个非常简单的 ExpressJS 服务器,它除了设置一个 cookie 什么都不做:
var express = require("express");
var cookieParser = require("cookie-parser");
var app = express();
app.use(cookieParser());
app.get("/", function (req, res) {
res.cookie("key", "value", {
domain: "192.168.1.102:3333",
path: "/",
expire: Date.now() + 3600000
});
res.send("Done");
});
var server = app.listen(3333, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
});
然后在我的 Roku 应用程序中(在主屏幕上)我有以下内容:
httpClient = Downloader()
httpClient.Send({
' My local IP address
url: "http://192.168.1.102:3333"
})
当我在我的 Roku 上 运行 时,我在调试日志中看到以下内容:
Headers:
<Component: roAssociativeArray> =
{
connection: "keep-alive"
content-length: "13"
content-type: "text/html; charset=utf-8"
date: "Tue, 11 Aug 2020 17:29:52 GMT"
etag: "W/"d-w+Ote5otCKx40dtR446Vz7wX66U""
set-cookie: "key=value; Path=/"
x-powered-by: "Express"
}
Adding cookies to cookie jar:
<Component: roArray> =
[
]
<Component: roArray> =
[
]
m.http.GetCookies(m.url.host, m.url.path)
和 m.http.GetCookies("", "/")
均未返回任何 cookie。但是你可以清楚地看到header中的cookie!那为什么我不能访问它?
请注意,m.url.host
是 192.168.1.102:3333
,m.url.path
是
(空白),以防有助于理解任何内容...
在为此工作了一整天后,我发现 Roku 无法正确处理 cookie 域中的 ports。当 192.168.1.102:3333
提供 cookie 时,Roku 在内部将 cookie 标记为属于 192.168.1.102
(无端口)。
这有两个含义:
- 如果使用
...; domain=...;
属性提供 cookie,并且此域包含端口,Roku 将完全无法解析set-cookie
header 并且不会提取任何 cookie - 如果提供的 cookie 没有 此属性,那么 Roku 将解析
set-cookie
header,但是GetCookies()
只会 return 如果未给定域 (""
) 或给定 port-less 域,则为 cookie。GetCookies("192.168.1.102", "/")
return cookie 但GetCookies("192.168.1.102:3333", "/")
没有
因为我的代码的目的是在多个 roUrlTransfer 实例之间共享 cookie,所以使用 GetCookies("", "/")
获取 all cookie 是可以接受的,所以我们将修改我们的back-end 从我们的 set-cookie
headers
...; domain=...;
属性