当请求到达Lift时,您可以跳过几个点,并控制Lift执行的操作,发回不同类型的响应或控制访问。本章通过不同种类LiftResponse
和配置的例子来看管道 。
您可以从Lift pipeline wiki页面中获得有关管道的详细信息,包括图表。
有关本章附带的源代码,请参阅https://github.com/LiftCookbook/cookbook_pipeline。
您想要调试请求,并查看到达Lift应用程序的内容。
onBeginServicing
在Boot.scala中添加一个函数来记录请求。 例如:
LiftRules
.
onBeginServicing
.
append
{
case
r
=>
println
(
"Received: "
+
r
)
}
该onBeginServicing
电话在Lift管道早期被称为,在 S
设置之前,在Lift有机会404您的请求之前。它期望的功能签名是Req => Unit
。我们只是记录,但功能可以用于其他目的。
如果您只想选择某些路径,您可以。例如,要跟踪所有请求开始/ paypal:
LiftRules
.
onBeginServicing
.
append
{
case
r
@
Req
(
"paypal"
::
_
),
_
,
_
)
=>
println
(
r
)
}
此模式将匹配任何请求开始/ paypal,并且我们忽略请求的后缀(如果有)和请求的类型(例如,GET,POST等)。
还有LiftRules.early
,以前叫过onBeginServicing
。它期望的HTTPRequest => Unit
功能,所以是一个小电平低于所述Req
中使用onBeginServicing
。但是,所有通过Lift的请求都将被调用。要查看差异,您可以将请求标记为容器本身应该处理的内容:
LiftRules
.
liftRequest
.
append
{
case
Req
(
"robots"
::
_
,
_
,
_
)
=>
false
}
有了这一点,对robots.txt的请求将被记录,LiftRules.early
但不会使其成为本配方中描述的任何其他方法。
如果你需要访问状态(例如,S
),使用earlyInStateful
,这是基于Box[Req]
不是Req
:
LiftRules
.
earlyInStateful
.
append
{
case
Full
(
r
)
=>
// access S here
case
_
=>
}
你的earlyInStateful
函数可能被调用两次。这将在新的会话建立时发生。您可以通过仅在运行的Lift会话中的请求匹配来防止此情况:
LiftRules
.
earlyInStateful
.
append
{
case
Full
(
r
)
if
LiftRules
.
getLiftSession
(
r
).
running_?
=>
// access S here
case
_
=>
}
最后,还有一个earlyInStateless
,就像一样earlyInStateful
,Box[Req]
但在其他方面是一样的onBeginServicing
。它是在early
前后触发的earlyInStateful
。
作为总结,本方法中描述的功能按以下顺序调用:
LiftRules.early
LiftRules.onBeginServicing
LiftRules.earlyInStateless
LiftRules.earlyInStateful
如果你需要抓住一个请求的结尾,还onEndServicing
可以给出一个类型的函数 (Req, Box[LiftResponse]) => Unit
。
“运行无状态”描述了如何强制请求成为无状态。
您要在会话创建或销毁时执行操作。
利用钩子LiftSession
。例如,在Boot.scala中:
LiftSession
.
afterSessionCreate
::=
(
(
s
:
LiftSession
,
r
:
Req
)
=>
println
(
"Session created"
)
)
LiftSession
.
onBeginServicing
::=
(
(
s
:
LiftSession
,
r
:
Req
)
=>
println
(
"Processing request"
)
)
LiftSession
.
onShutdownSession
::=
(
(
s
:
LiftSession
)
=>
println
(
"Session going away"
)
)
如果请求路径被标记为无状态通道 LiftRules.statelessReqTest
,则该示例将仅执行该 onBeginServicing
功能。
挂钩LiftSession
允许您在会话生命周期中的各个点插入代码:当会话创建时,在服务请求开始时,维修后,会话即将关闭,关机时等。管道本章开头提到的图表是这些阶段的有用指南。
会话挂钩列表如下:
onSetupSession
afterSessionCreate
onSetupSession
函数后,这将被调用。
onBeginServicing
onEndServicing
onAboutToShutdownSession
onShutdownSession
onAboutToShutdownSession
功能运行后,这将被调用。
如果您正在测试这些挂钩,您可能希望使会话的时间比默认在Lift中使用的30分钟不活动更快。为此,请提供一个毫秒值LiftRules.sessionInactivityTimeout
:
// 30 second inactivity timeout
LiftRules
.
sessionInactivityTimeout
.
default
.
set
(
Full
(
1000L
*
30
))
还有另外两个钩子LiftSession
:onSessionActivate
和onSessionPassivate
。如果您正在以分布式模式处理servlet容器,并希望在servlet HTTP会话即将被串行化(钝化)并在容器实例之间反序列化(激活)时收到通知,那么这些可能是有用的。这些钩子很少使用。
请注意,提升会话与HTTP会话不同。将网桥从HTTP会话提升到自己的会话管理。这在探索提升中有一些细节。
会议管理在“ 探索提升”第9.5节中讨论。
“运行无状态”显示如何运行没有状态。
当您的Lift应用程序关闭时,您希望执行一些代码。
附加到LiftRules.unloadHooks
:
LiftRules
.
unloadHooks
.
append
(
()
=>
println
(
"Shutting down"
)
)
您附加类型() => Unit
的功能unloadHooks
,并且这些功能在Lift处理程序结束时运行,会话已被破坏后,Lift actors已关闭,请求已完成处理。
这是以Java servlet规范的话来触发的,“通过Web容器向过滤器指示它被取消服务”。
“定期运行任务”包括使用卸载钩子的示例。
您希望强制您的应用程序在HTTP级别是无状态的。
在Boot.scala中:
LiftRules
.
enableContainerSessions
=
false
LiftRules
.
statelessReqTest
.
append
{
case
_
=>
true
}
所有请求现在将被视为无状态。任何尝试使用状态,例如通过SessionVar
例如,将在开发人员模式下触发警告:“访问Lift的无状态模式的状态特征,状态操作将不会完成。
HTTP会话创建通过控制enableContainerSessions
,并应用于所有请求。将此值保留在default(true
)允许更细粒度地控制哪些请求是无状态的。
使用statelessReqTest
允许您根据StatelessReqTest
案例类决定 请求是否应为无状态(true
)或不是(false
)。例如:
def
asset
(
file
:
String
)
=
List
(
".js"
,
".gif"
,
".css"
).
exists
(
file
.
endsWith
)
LiftRules
.
statelessReqTest
.
append
{
case
StatelessReqTest
(
"index"
::
Nil
,
httpReq
)
=>
true
case
StatelessReqTest
(
List
(
_
,
file
),
_
)
if
asset
(
file
)
=>
true
}
这个例子只会使索引页面和任何GIF,JavaScript和CSS文件无状态。该httpReq
部分是一个HTTPRequest
实例,允许您根据请求的内容(Cookie,用户代理等)作出决定。
另一个选项是LiftRules.statelessDispatch
,它允许您注册一个返回的函数LiftResponse
。这将在没有会话的情况下执行,并且方便基于REST的服务。
如果您只需要将条目标记SiteMap
为无状态,则可以:
Menu
.
i
(
"Stateless Page"
)
/
"demo"
>>
Stateless
一个请求/演示将被处理没有状态。
第4章包含Lift中基于REST的服务的配方。
Lift提供进一步的处理无状态请求的细节。
Lift 2.2中介绍了无状态请求控制。邮件列表中的公告提供了更多的细节。
您想要围绕所有请求的包装器来捕获异常并向用户显示某些内容。
在Boot.scala中声明一个异常处理程序:
LiftRules
.
exceptionHandler
.
prepend
{
case
(
runMode
,
request
,
exception
)
=>
logger
.
error
(
"Failed at: "
+
request
.
uri
)
InternalServerErrorResponse
()
}
在此示例中,所有运行模式下所有请求的所有异常都被匹配,导致记录错误,并返回500(内部服务器)错误。
您添加的部分功能exceptionHandler
需要返回 LiftResponse
(即,要发送到浏览器的东西)。默认的行为是返回一个XhtmlResponse
,其中 Props.RunModes.Development
给出了异常的详细信息,而在所有其他运行模式中,简单地说:“发生了意外事件。
你可以返回任何类型的LiftResponse
,包括RedirectResponse
, JsonResponse
,XmlResponse
,JavaScriptResponse
,等。
前面的例子只是发送标准的500错误。这对您的用户来说不是很有帮助。另一种方法是呈现自定义消息,但保留500状态代码,这对于外部站点监视服务将是有用的,如果您使用它们:
LiftRules
.
exceptionHandler
.
prepend
{
case
(
runMode
,
req
,
exception
)
=>
logger
.
error
(
"Failed at: "
+
req
.
uri
)
val
content
=
S
.
render
(<
lift
:
embed
what
=
"500"
/>,
req
.
request
)
XmlResponse
(
content
.
head
,
500
,
"text/html"
,
req
.
cookies
)
}
这里我们发回一个500状态代码的回复,但内容是 Node
运行src / main / webapp / template-hidden / 500.html的结果。使用要向用户显示的消息创建该文件:
500
data-lift-content-id=
"main"
>
id=
"main"
data-lift=
"surround?with=default;at=content"
>
有什么问题!
这是我们的错 - 抱歉
您还可以控制处理Ajax请求时发送给客户端的内容。在以下示例中,我们只是在Ajax POST请求上匹配,并将自定义JavaScript返回到浏览器:
import
net.liftweb.http.js.JsCmds._
val
ajax
=
LiftRules
.
ajaxPath
LiftRules
.
exceptionHandler
.
prepend
{
case
(
mode
,
Req
(
ajax
::
_
,
_
,
PostRequest
),
ex
)
=>
logger
.
error
(
"Error handing ajax"
)
JavaScriptResponse
(
Alert
(
"Boom!"
))
}
您可以通过创建始终产生异常的Ajax按钮来测试此处理代码:
package
code.snippet
import
net.liftweb.util.Helpers._
import
net.liftweb.http.SHtml
class
ThrowsException
{
private
def
fail
=
throw
new
Error
(
"not implemented"
)
def
render
=
"*"
#>
SHtml
.
ajaxButton
(
"Press Me"
,
()
=>
fail
)
}
此Ajax示例将跳过Lift对Ajax错误的默认行为。默认是重试Ajax命令三次(LiftRules.ajaxRetryCount
),然后执行 LiftRules.ajaxDefaultFailure
,这将弹出一个对话框,说:“此时无法联系服务器。
“自定义404页面”介绍如何创建自定义404(未找到)页面。
您想将内容流传回到Web客户端。
使用OutputStreamResponse
,传递一个函数,将写入 OutputStream
该提供用品。
在这个例子中,我们将通过REST服务流式传输所有的整数,
package
code.rest
import
net.liftweb.http.
{
Req
,
OutputStreamResponse
}
import
net.liftweb.http.rest._
object
Numbers
extends
RestHelper
{
// Convert a number to a String, and then to UTF-8 bytes
// to send down the output stream.
def
num2bytes
(
x
:
Int
)
=
(
x
+
"\n"
)
getBytes
(
"utf-8"
)
// Generate numbers using a Scala stream:
def
infinite
=
Stream
.
from
(
1
).
map
(
num2bytes
)
serve
{
case
Req
(
"numbers"
::
Nil
,
_
,
_
)
=>
OutputStreamResponse
(
out
=>
infinite
.
foreach
(
out
.
write
)
)
}
}
Scala的Stream
类是一种用惰性评估来生成序列的方式。所生成的值被infinite
用作示例数据流回到客户端。
将其连接到Boot.scala中的Lift中:
LiftRules
.
dispatch
.
append
(
Numbers
)
访问http://127.0.0.1:8080/numbers将生成200个状态代码,并从1开始生成整数。数字的制作速度非常快,所以你可能不想在Web浏览器中尝试这个从更容易停止的东西,如cURL。
OutputStreamResponse
期待一种类型的功能OutputStream => Unit
。该 OutputStream
参数是输出流给客户端。这意味着我们写入流的字节写入客户端。示例中的相关行为:
OutputStreamResponse
(
out
=>
infinite
.
foreach
(
out
.
write
))
我们正在使用Java write(byte[])
上的方法out
,OutputStream
并将其Array[Byte]
从我们的infinite
流中生成。
请注意,OutputStreamResponse
在其范围之外执行S
。这意味着如果您需要访问会话中的任何内容,请在您传递给的功能之外执行此操作OutputStreamResponse
。
为了更好地控制状态代码,标题和Cookie,OutputStreamResponse
对象有各种各样的签名。对于最多的控件,创建一个OutputStreamResponse
类的实例:
case
class
OutputStreamResponse
(
out
:
(
OutputStream
)
=>
Unit
,
size
:
Long
,
headers
:
List
[(
String
,String
)],
cookies
:
List
[
HTTPCookie
],
code
:
Int
)
请注意,设置size
以-1
使Content-Length
头部被跳过。
有两种相关类型的回应:InMemoryResponse
和 StreamingResponse
。
InMemoryResponse
如果您已经将完整的内容组合发送给客户端,这是非常有用的。签名很简单:
case
class
InMemoryResponse
(
data
:
Array
[
Byte
],
headers
:
List
[(
String
,String
)],
cookies
:
List
[
HTTPCookie
],
code
:
Int
)
例如,我们可以修改配方,并强制我们infinite
的数字序列来产生前几个数字作为Array[Byte]
内存:
import
net.liftweb.util.Helpers._
serve
{
case
Req
(
AsInt
(
n
)
::
Nil
,
_
,
_
)
=>
InMemoryResponse
(
infinite
.
take
(
n
).
toArray
.
flatten
,
Nil
,
Nil
,
200
)
}
AsInt
Lift中的帮助器匹配整数,这意味着以数字开头的请求匹配,我们将从无限序列中返回许多数字。我们不设置标题或Cookie,此请求会产生您期望的内容:
$ curl http://127.0.0.1:8080/3 1 2 3
StreamingResponse
将字节拉入输出流。这与OutputStreamResponse
您将数据推送到客户端的情况形成对比。
通过为类提供read
可以从中读取的方法来构造此类型的响应:
case
class
StreamingResponse
(
data
:
{
def
read
(
buf:
Array
[
Byte
])
:
Int
},
onEnd
:
()
=>
Unit
,
size
:
Long
,
headers
:
List
[(
String
,String
)],
cookies
:
List
[
HTTPCookie
],
code
:
Int
)
请注意使用结构类型作为data
参数。read
在这里可以给出任何具有匹配方法的内容,包括java.io.InputStream
对象,意思StreamingResponse
可以作为从输入到输出的管道。Lift将8K块从您那里StreamingResponse
发送给客户端。
您的data
read
函数应遵循Java IO的语义,并返回“读入缓冲区的总字节数,如果没有达到数据流,则返回-1。
“服务视频”提供了通过REST流式传输视频数据的示例。
JavaDoc为该方法InputStream
提供了完整的合同read
。
您有一个磁盘上的文件,并且您希望允许用户下载文件,但只允许用户下载。如果不允许,你想解释为什么。
使用RestHelper
服务的文件或说明页面。
例如,假设我们有/ tmp /重要文件,我们只希望选择的请求从/ download /重要 URL 下载该文件。其结构将是:
package
code.rest
import
net.liftweb.util.Helpers._
import
net.liftweb.http.rest.RestHelper
import
net.liftweb.http.
{
StreamingResponse
,
LiftResponse
,
RedirectResponse
}
import
net.liftweb.common.
{
Box
,
Full
}
import
java.io.
{
FileInputStream
,
File
}
object
DownloadService
extends
RestHelper
{
// (code explained below to go here)
serve
{
case
"download"
::
Known
(
fileId
)
::
Nil
Get
req
=>
if
(
permitted
)
fileResponse
(
fileId
)
else
Full
(
RedirectResponse
(
"/sorry"
))
}
}
我们允许用户下载“已知”文件。也就是说,我们批准访问的文件。我们这样做是因为打开文件系统到任何未过滤的最终用户输入几乎意味着您的服务器将被泄露。
对于我们的例子,Known
正在检查静态名称列表:
val
knownFiles
=
List
(
"important"
)
object
Known
{
def
unapply
(
fileId
:
String
)
:
Option
[
String
]
=
knownFiles
.
find
(
_
==
fileId
)
}
对于这些已知资源的请求,我们将REST请求转换为Box[LiftResponse]
。对于允许的访问,我们提供文件:
private
def
permitted
=
scala
.
math
.
random
<
0.5d
private
def
fileResponse
(
fileId
:
String
)
:
Box
[
LiftResponse
]
=
for
{
file
<-
Box
!!
new
File
(
"/tmp/"
+
fileId
)
input
<-
tryo
(
new
FileInputStream
(
file
))
}
yield
StreamingResponse
(
input
,
()
=>
input
.
close
,
file
.
length
,
headers
=
Nil
,
cookies
=
Nil
,
200
)
如果没有授权,用户被重定向到/sorry.html。
所有这些都连接到Boot.scala中的Lift中:
LiftRules
.
dispatch
.
append
(
DownloadService
)
通过将请求转为a Box[LiftResponse]
,我们可以提供文件,将用户发送到不同的页面,并允许Lift处理404(Empty
)情况。
如果我们增加了一个测试,看看文件中的磁盘上存在fileResponse
,这将导致该方法计算为Empty
丢失的文件,由于代码代表触发一个404,如果该文件不存在,则tryo
会给我们一个Failure
是会变成一个404错误与一个“/ tmp /重要(没有这样的文件或目录)”。
因为我们通过Known
提取器测试已知资源,作为/ download /的模式的一部分,未知资源将不会传递到我们的File
访问代码。再次,Lift将为这些返回404。
警卫表情也可用于这些情况:
serve
{
case
"download"
::
Known
(
id
)
::
Nil
Get
_
if
permitted
=>
fileResponse
(
id
)
case
"download"
::
_
Get
req
=>
RedirectResponse
(
"/sorry"
)
}
您可以根据您希望代码查找和工作的方式,将您的响应中的提取器,警卫和条件混合并匹配。
第24章:Scala中的编程提取器。
您需要根据HTTP标头的值控制对页面的访问。
使用自定义If
在SiteMap
:
val
HeaderRequired
=
If
(
()
=>
S
.
request
.
map
(
_
.
header
(
"ALLOWED"
)
==
Full
(
"YES"
))
openOr
false
,
"Access not allowed"
)
// Build SiteMap
val
entries
=
List
(
Menu
.
i
(
"Header Required"
)
/
"header-required"
>>
HeaderRequired
)
在这个例子中,首标required.html只能如果该请求包括称为HTTP报头观察ALLOWED
用的值YES
。对该页面的任何其他请求将被重定向到“不允许访问”的提升错误通知。
这可以使用cURL这样的工具从命令行进行测试:
$ curl http://127.0.0.1:8080/header-required.html -H“允许:是”
该If
测试可确保() => Boolean
您提供的第一个参数函数返回true
页面之前它适用于所示。在这个例子中,true
如果请求包含一个调用的头ALLOWED
,并且该头的可选值是Full("YES")
。这是一个LocParam
(位置参数)修改该SiteMap
项目。它可以附加到您想要使用该>>
方法的任何菜单项。
请注意,没有标题,测试将为false。这意味着链接到页面将不会出现在生成的菜单中Menu.builder
。
If()
如果用户尝试访问该页面时测试不正确,则第二个参数是Lift执行。这是一个() => LiftResponse
功能。这意味着你可以返回任何你喜欢的,包括重定向到其他页面。在这个例子中,我们正在利用一个方便的隐式会话String
(“不允许访问”)到重定向的通知,这将使用户进入主页。
如果您访问页面而没有标题,您会看到一条通知,指出“不允许访问”。这将是网站的主页,但这只是默认。您可以通过LiftRules.siteMapFailRedirectLocation
在Boot.scala中设置来请求Lift显示不同的页面:
LiftRules
.
siteMapFailRedirectLocation
=
"static"
::
"permission"
::
Nil
如果然后尝试访问header-required.html而不使用头文件集,则将被重定向到/ static / permission,并显示您在该页面中放置的内容。
Lift维基提供了Lift的摘要SiteMap
和您可以在站点地图条目中包含的测试。
“ 探索Lift”第7章还有“SiteMap和访问控制”,“ 提升行动”(Perrett,2012,Manning Publications,Co.)第7章中的进一步细节。
你有一个需要访问的API来调用它HttpServletRequest
。
演员S.request
:
import
net.liftweb.http.S
import
net.liftweb.http.provider.servlet.HTTPRequestServlet
import
javax.servlet.http.HttpServletRequest
def
servletRequest
:
Box
[
HttpServletRequest
]
=
for
{
req
<-
S
.
request
inner
<-
Box
.
asA
[
HTTPRequestServlet
](
req
.
request
)
}
yield
inner
.
req
然后,您可以调用API:
servletRequest
.
foreach
{
r
=>
yourApiCall
(
r
)
}
从低级HTTP请求中提取摘要,以及您应用程序正在运行的servlet容器的详细信息。但是,如果您绝对需要,可以放心,有一种方法可以恢复到低级别。
请注意,结果servletRequest
是a Box
,因为评估时可能没有请求servletRequest
- 或者您可能有一天到不同部署环境的端口,而不是在标准的Java servlet容器上运行。
由于您的代码将直接依赖于Java Servlet API,因此您需要在SBT构建中包含此依赖关系:
"javax.servlet"
%
"servlet-api"
%
"2.5"
%
"provided"
您希望确保客户端正在使用HTTPS。
earlyResponse
在Boot.scala中添加一个功能,将 HTTP请求重定向到HTTPS等效项。例如:
LiftRules
.
earlyResponse
.
append
{
(
req
:
Req
)
=>
if
(
req
.
request
.
scheme
!=
"https"
)
{
val
uriAndQuery
=
req
.
uri
+
(
req
.
request
.
queryString
.
map
(
s
=>
"?"
+
s
)
openOr
""
)
val
uri
=
"https://%s%s"
.
format
(
req
.
request
.
serverName
,
uriAndQuery
)
Full
(
PermRedirectResponse
(
uri
,
req
,
req
.
cookies
:
_
*
))
}
else
Empty
}
该earlyResponse
呼叫在Lift管道称为早期。它用于在处理请求之前执行代码,如果需要,则退出管道并返回响应。预期的功能签名是 Req => Box[LiftResponse]
。
在这个例子中,我们正在测试一个不是“https”的请求,然后制定一个启动“https”的新URL,并附加其余的原始URL和任何查询参数。创建此项后,我们会将重定向返回到新的URL,以及设置的任何Cookie。
通过评估Empty
其他请求(即HTTPS请求),Lift将继续照常通过管道传递请求。
使用正确的方案来确保请求的理想方法将是通过Web服务器配置,如Apache或Nginx。这在某些情况下是不可能的,例如将应用程序部署到诸如CloudBees的平台即服务(PaaS)时。
对于Amazon Elastic Load Balancer,请注意,您需要使用 X-Forwarded-Proto
头来检测HTTPS。如 “弹性负载平衡概述 ” 文档中所述,“您的服务器访问日志仅包含服务器和负载平衡器之间使用的协议;它们不包含有关客户端和负载平衡器之间使用的协议的信息。
在这种情况下,将测试修改 req.request.scheme != "https"
为:
req
.
header
(
"X-Forwarded-Proto"
)
!=
Full
(
"https"
)
到目前为止,我们已经将所有请求重定向到HTTPS。如果您只需要少量页面来担心,可以使用自定义的位置参数在SiteMap
作为替代:
val
entries
=
List
(
Menu
.
i
(
"Home"
)
/
"index"
,
Menu
.
i
(
"Login"
)
/
"login"
>>
HttpsOnly
)
我们有两个位置,我们将登录页面标记为必须通过HTTPS。 HttpsOnly
是位置参数。它不是内置的,但我们可以从Lift中包含的构建块和我们已经编写的代码定义它:
// Given a request, turn it into a redirect to the HTTPS version of the page
def
redirection
(
req
:
Req
)
:
LiftResponse
=
{
val
uriAndQuery
=
req
.
uri
+
(
req
.
request
.
queryString
.
map
(
s
=>
"?"
+
s
)
openOr
""
)
val
uri
=
"https://%s%s"
.
format
(
req
.
request
.
serverName
,
uriAndQuery
)
PermRedirectResponse
(
uri
,
req
,
req
.
cookies
:
_
*
)
}
// If the request is HTTP, give us a redirect to HTTPS
def
httpsRedirect
:
Box
[
LiftResponse
]
=
for
{
req
<-
S
.
request
scheme
<-
req
.
header
(
"X-Forwarded-Proto"
)
if
scheme
==
"http"
}
yield
redirection
(
req
)
val
HttpsOnly
=
TestAccess
(
()
=>
httpsRedirect
)
对我们想要发生的事情的回顾:任何标记为的菜单项HttpsOnly
都应将其重定向到HTTPS,除非它已经是HTTPS。我们可以TestAccess
用来实现这一点。给定的功能TestAccess
必须评估为a Box[LiftResponse]
:如果是Empty
,请求正常进行; 如果是Full
,请求被重定向到框的内容。
我们的HttpsOnly
实现是调用httpsRedirect
,理解选择请求,检查方案,只有它是“http”,它产生一个Full[LiftResponse]
。这就是HTTPS请求被允许通过(httpsRedirect
评估Empty
),但HTTP请求被转换Full[PermRedirectResponse]
并TestAccess
执行重定向。
值得注意的是,这也方便了当地的发展。如果本地X-Forwarded-Proto
在请求中没有标题,HTTPS重定向将不被触发。当然,假设X-Forwarded-Proto
检查适用于您。相反,如果你正在使用的req.request.scheme
检查,你也可能要破例在开发模式下运行(Props.devMode
评估为true
发展模式)。