Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
2633b4e9
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2633b4e9
编写于
12月 14, 2016
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
RedirectView applies encodeUri + polish
上级
c66dd017
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
107 addition
and
127 deletion
+107
-127
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/RedirectView.java
...pringframework/web/reactive/result/view/RedirectView.java
+106
-126
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/RedirectViewTests.java
...framework/web/reactive/result/view/RedirectViewTests.java
+1
-1
未找到文件。
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/RedirectView.java
浏览文件 @
2633b4e9
...
...
@@ -18,7 +18,7 @@ package org.springframework.web.reactive.result.view;
import
java.io.UnsupportedEncodingException
;
import
java.net.URI
;
import
java.nio.charset.
Charset
;
import
java.nio.charset.
StandardCharsets
;
import
java.util.Collections
;
import
java.util.Locale
;
import
java.util.Map
;
...
...
@@ -40,21 +40,15 @@ import org.springframework.web.util.UriComponentsBuilder;
import
org.springframework.web.util.UriUtils
;
/**
* View that redirects to an absolute or context relative URL. The URL may be a
URI
*
template in which case the URI template variables will be replaced with values
*
available in the model
.
* View that redirects to an absolute or context relative URL. The URL may be a
*
URI template in which case the URI template variables will be replaced with
*
values from the model or with URI variables from the current request
.
*
* <p>A URL for this view is supposed to be a HTTP redirect which does the redirect via
* sending a {@literal 3xx} status code. By default {@link HttpStatus#SEE_OTHER} is used.
* If HTTP 1.0 compatibility is needed, {@link HttpStatus#FOUND} code can be set via
* {@link #setStatusCode(HttpStatus)}.
*
* <p>Note that the default value for the "contextRelative" flag is true.
* With the flag on, URLs starting with "/" are considered relative to the web application
* context path, while with this flag off they are considered relative to the web server
* root.
* <p>By default {@link HttpStatus#SEE_OTHER} is used but alternate status
* codes may be via constructor or setters arguments.
*
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
* @since 5.0
*/
public
class
RedirectView
extends
AbstractUrlBasedView
{
...
...
@@ -78,21 +72,17 @@ public class RedirectView extends AbstractUrlBasedView {
}
/**
* Create a new {@code RedirectView} with the given
URL and the {@link HttpStatus#SEE_OTHER}
*
status code which is the correct code for HTTP 1.1 clients
.
* Create a new {@code RedirectView} with the given
redirect URL.
*
Status code {@link HttpStatus#SEE_OTHER} is used by default
.
*/
public
RedirectView
(
String
redirectUrl
)
{
super
(
redirectUrl
);
}
/**
* Create a new {@code RedirectView} with the given redirect URL ans status code. Most
* frequently used ones are:
* <ul>
* <li>{@link HttpStatus#SEE_OTHER} : temporary redirect for HTTP 1.1 compatible clients</li>
* <li>{@link HttpStatus#FOUND} : temporary redirect for HTTP 1.0 compatible clients</li>
* <li>{@link HttpStatus#MOVED_PERMANENTLY} : permanent redirect</li>
* </ul>
* Create a new {@code RedirectView} with the given URL and an alternate
* redirect status code such as {@link HttpStatus#TEMPORARY_REDIRECT} or
* {@link HttpStatus#PERMANENT_REDIRECT}.
*/
public
RedirectView
(
String
redirectUrl
,
HttpStatus
statusCode
)
{
super
(
redirectUrl
);
...
...
@@ -101,7 +91,7 @@ public class RedirectView extends AbstractUrlBasedView {
/**
*
Set whether to interpret a given URL
that starts with a slash ("/")
*
Whether to interpret a given redirect URLs
that starts with a slash ("/")
* as relative to the current context path ({@code true}, the default) or to
* the web server root ({@code false}).
*/
...
...
@@ -110,38 +100,32 @@ public class RedirectView extends AbstractUrlBasedView {
}
/**
* Return whether to interpret a given URL that starts with a slash ("/")
* as relative to the current context path ("true") or to the web server
* root ("false").
* @return
* Whether to interpret URLs as relative to the current context path.
*/
public
boolean
isContextRelative
()
{
return
contextRelative
;
return
this
.
contextRelative
;
}
/**
* Set the redirect status code. Most frequently used ones are:
* <ul>
* <li>{@link HttpStatus#SEE_OTHER} : temporary redirect for HTTP 1.1 compatible clients</li>
* <li>{@link HttpStatus#FOUND} : temporary redirect for HTTP 1.0 compatible clients</li>
* <li>{@link HttpStatus#MOVED_PERMANENTLY} : permanent redirect</li>
* </ul>
* Set an alternate redirect status code such as
* {@link HttpStatus#TEMPORARY_REDIRECT} or
* {@link HttpStatus#PERMANENT_REDIRECT}.
*/
public
void
setStatusCode
(
HttpStatus
statusCode
)
{
Assert
.
notNull
(
statusCode
,
"HttpStatus must not be null"
);
Assert
.
isTrue
(
statusCode
.
is3xxRedirection
(),
"
HttpStatus m
ust be a redirection (3xx status code)"
);
Assert
.
isTrue
(
statusCode
.
is3xxRedirection
(),
"
M
ust be a redirection (3xx status code)"
);
this
.
statusCode
=
statusCode
;
}
/**
* Get the redirect status code.
* Get the redirect status code
to use
.
*/
public
HttpStatus
getStatusCode
()
{
return
statusCode
;
return
this
.
statusCode
;
}
/**
*
Set whether to append the query string of the current URL to the redirected
URL
*
Whether to append the query string of the current URL to the redirect
URL
* ({@code true}) or not ({@code false}, the default).
*/
public
void
setPropagateQuery
(
boolean
propagateQuery
)
{
...
...
@@ -149,20 +133,19 @@ public class RedirectView extends AbstractUrlBasedView {
}
/**
* Return whether the query string of the current URL is appended to the redirected URL
* ({@code true}) or not ({@code false}).
* Whether the query string of the current URL is appended to the redirect URL.
*/
public
boolean
isPropagateQuery
()
{
return
propagateQuery
;
return
this
.
propagateQuery
;
}
/**
* Configure one or more hosts associated with the application.
* All other hosts will be considered external hosts.
* <p>In effect
, this property
provides a way turn off encoding via
* {@link
javax.servlet.http.HttpServletResponse#encodeRedirectURL
} for URLs that have a
* host and that host is not listed as a known host
when using a Servlet based engine
.
* <p>If not set (the default) all
URLs are encoded through the response
.
* <p>In effect
this
provides a way turn off encoding via
* {@link
ServerHttpResponse#encodeUrl(String)
} for URLs that have a
* host and that host is not listed as a known host.
* <p>If not set (the default) all
redirect URLs are encoded
.
* @param hosts one or more application hosts
*/
public
void
setHosts
(
String
...
hosts
)
{
...
...
@@ -176,124 +159,134 @@ public class RedirectView extends AbstractUrlBasedView {
return
this
.
hosts
;
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
super
.
afterPropertiesSet
();
if
(
getStatusCode
()
==
null
)
{
throw
new
IllegalArgumentException
(
"Property 'statusCode' is required"
);
}
}
@Override
public
boolean
checkResourceExists
(
Locale
locale
)
throws
Exception
{
return
true
;
}
/**
* Convert model to request parameters and redirect to the given URL.
* @see #sendRedirect
*/
@Override
protected
Mono
<
Void
>
renderInternal
(
Map
<
String
,
Object
>
model
,
MediaType
contentType
,
ServerWebExchange
exchange
)
{
String
targetUrl
=
createTargetUrl
(
model
,
exchange
);
return
sendRedirect
(
exchange
,
targetUrl
);
return
sendRedirect
(
targetUrl
,
exchange
);
}
/**
* Create the target URL by checking if the redirect string is a URI template first,
* expanding it with the given model, and then optionally appending simple type model
* attributes as query String parameters.
* Create the target URL if necessary pre-pending the contextPath, expanding
* URI template variables, and appending the current request query.
*/
protected
final
String
createTargetUrl
(
Map
<
String
,
Object
>
model
,
ServerWebExchange
exchange
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
// Prepare target URL.
StringBuilder
targetUrl
=
new
StringBuilder
();
if
(
this
.
contextRelative
&&
getUrl
().
startsWith
(
"/"
))
{
// Do not apply context path to relative URLs.
targetUrl
.
append
(
request
.
getContextPath
());
if
(
isContextRelative
()
&&
getUrl
().
startsWith
(
"/"
))
{
targetUrl
.
append
(
exchange
.
getRequest
().
getContextPath
());
}
targetUrl
.
append
(
getUrl
());
Charset
charset
=
this
.
getDefaultCharset
();
if
(
StringUtils
.
hasText
(
targetUrl
))
{
Map
<
String
,
String
>
variables
=
getCurrentReques
tUriVariables
(
exchange
);
targetUrl
=
replaceUriTemplateVariables
(
targetUrl
.
toString
(),
model
,
variables
,
charset
);
Map
<
String
,
String
>
uriVars
=
getCurren
tUriVariables
(
exchange
);
targetUrl
=
expandTargetUrlTemplate
(
targetUrl
.
toString
(),
model
,
uriVars
);
}
if
(
this
.
propagateQuery
)
{
appendCurrentQueryParams
(
targetUrl
,
request
);
if
(
isPropagateQuery
())
{
targetUrl
=
appendCurrentRequestQuery
(
targetUrl
.
toString
(),
exchange
.
getRequest
());
}
return
targetUrl
.
toString
();
}
@SuppressWarnings
(
"unchecked"
)
private
Map
<
String
,
String
>
getCurrentUriVariables
(
ServerWebExchange
exchange
)
{
String
name
=
HandlerMapping
.
URI_TEMPLATE_VARIABLES_ATTRIBUTE
;
return
(
Map
<
String
,
String
>)
exchange
.
getAttribute
(
name
).
orElse
(
Collections
.
emptyMap
());
}
/**
* Replace URI template variables in the target URL with encoded model
* attributes or URI variables from the current request. Model attributes
* referenced in the URL are removed from the model.
* @param targetUrl the redirect URL
* @param model Map that contains model attributes
* @param currentUriVariables current request URI variables to use
* @param charset the charset to use
* Expand URI template variables in the target URL with either model
* attribute values or as a fallback with URI variable values from the
* current request. Values are encoded.
*/
protected
StringBuilder
replaceUriTemplateVariables
(
String
targetUrl
,
Map
<
String
,
Object
>
model
,
Map
<
String
,
String
>
currentUriVariables
,
Charset
charset
)
{
protected
StringBuilder
expandTargetUrlTemplate
(
String
targetUrl
,
Map
<
String
,
Object
>
model
,
Map
<
String
,
String
>
uriVariables
)
{
StringBuilder
result
=
new
StringBuilder
();
Matcher
matcher
=
URI_TEMPLATE_VARIABLE_PATTERN
.
matcher
(
targetUrl
);
boolean
found
=
matcher
.
find
();
if
(!
found
)
{
return
new
StringBuilder
(
targetUrl
);
}
StringBuilder
result
=
new
StringBuilder
();
int
endLastMatch
=
0
;
while
(
matcher
.
find
()
)
{
while
(
found
)
{
String
name
=
matcher
.
group
(
1
);
Object
value
=
(
model
.
containsKey
(
name
)
?
model
.
remove
(
name
)
:
currentUriVariables
.
get
(
name
));
if
(
value
==
null
)
{
throw
new
IllegalArgumentException
(
"Model has no value for key '"
+
name
+
"'"
);
}
Object
value
=
(
model
.
containsKey
(
name
)
?
model
.
get
(
name
)
:
uriVariables
.
get
(
name
));
Assert
.
notNull
(
value
,
"No value for URI variable '"
+
name
+
"'"
);
result
.
append
(
targetUrl
.
substring
(
endLastMatch
,
matcher
.
start
()));
try
{
result
.
append
(
UriUtils
.
encodePathSegment
(
value
.
toString
(),
charset
.
name
()));
}
catch
(
UnsupportedEncodingException
ex
)
{
throw
new
IllegalStateException
(
ex
);
}
result
.
append
(
encodeUriVariable
(
value
.
toString
()));
endLastMatch
=
matcher
.
end
();
found
=
matcher
.
find
();
}
result
.
append
(
targetUrl
.
substring
(
endLastMatch
,
targetUrl
.
length
()));
return
result
;
}
@SuppressWarnings
(
"unchecked"
)
private
Map
<
String
,
String
>
getCurrentRequestUriVariables
(
ServerWebExchange
exchange
)
{
String
name
=
HandlerMapping
.
URI_TEMPLATE_VARIABLES_ATTRIBUTE
;
return
(
Map
<
String
,
String
>)
exchange
.
getAttribute
(
name
).
orElse
(
Collections
.
emptyMap
());
private
String
encodeUriVariable
(
String
text
)
{
try
{
// Strict encoding of all reserved URI characters
return
UriUtils
.
encode
(
text
,
StandardCharsets
.
UTF_8
.
name
());
}
catch
(
UnsupportedEncodingException
ex
)
{
// Should never happen...
throw
new
IllegalStateException
(
ex
);
}
}
/**
* Append the query string of the current request to the target redirect URL.
* @param targetUrl the StringBuilder to append the properties to
* @param request the current request
* Append the query of the current request to the target redirect URL.
*/
protected
void
appendCurrentQueryParams
(
StringBuilder
targetUrl
,
ServerHttpRequest
request
)
{
String
query
=
request
.
getURI
().
getQuery
();
if
(
StringUtils
.
hasText
(
query
))
{
// Extract anchor fragment, if any.
String
fragment
=
null
;
int
anchorIndex
=
targetUrl
.
indexOf
(
"#"
);
if
(
anchorIndex
>
-
1
)
{
fragment
=
targetUrl
.
substring
(
anchorIndex
);
targetUrl
.
delete
(
anchorIndex
,
targetUrl
.
length
());
}
protected
StringBuilder
appendCurrentRequestQuery
(
String
targetUrl
,
ServerHttpRequest
request
)
{
String
query
=
request
.
getURI
().
getRawQuery
();
if
(!
StringUtils
.
hasText
(
query
))
{
return
new
StringBuilder
(
targetUrl
);
}
if
(
targetUrl
.
toString
().
indexOf
(
'?'
)
<
0
)
{
targetUrl
.
append
(
'?'
).
append
(
query
);
}
else
{
targetUrl
.
append
(
'&'
).
append
(
query
);
}
// Append anchor fragment, if any, to end of URL.
if
(
fragment
!=
null
)
{
targetUrl
.
append
(
fragment
);
}
int
index
=
targetUrl
.
indexOf
(
"#"
);
String
fragment
=
(
index
>
-
1
?
targetUrl
.
substring
(
index
)
:
null
);
StringBuilder
result
=
new
StringBuilder
();
result
.
append
(
index
!=
-
1
?
targetUrl
.
substring
(
0
,
index
)
:
targetUrl
);
result
.
append
(
targetUrl
.
indexOf
(
'?'
)
<
0
?
'?'
:
'&'
).
append
(
query
);
if
(
fragment
!=
null
)
{
result
.
append
(
fragment
);
}
return
result
;
}
/**
* Send a redirect back to the HTTP client
* @param exchange current HTTP exchange
* @param targetUrl the target URL to redirect to
* @param exchange current exchange
*/
protected
Mono
<
Void
>
sendRedirect
(
S
erverWebExchange
exchange
,
String
targetUrl
)
{
protected
Mono
<
Void
>
sendRedirect
(
S
tring
targetUrl
,
ServerWebExchange
exchange
)
{
ServerHttpResponse
response
=
exchange
.
getResponse
();
// TODO Support encoding redirect URL as ServerHttpResponse level when SPR-14529 will be fixed
response
.
getHeaders
().
setLocation
(
URI
.
create
(
targetUrl
));
response
.
setStatusCode
(
this
.
statusCode
);
String
encodedURL
=
(
isRemoteHost
(
targetUrl
)
?
targetUrl
:
response
.
encodeUrl
(
targetUrl
));
response
.
getHeaders
().
setLocation
(
URI
.
create
(
encodedURL
));
response
.
setStatusCode
(
getStatusCode
()
);
return
Mono
.
empty
();
}
...
...
@@ -322,17 +315,4 @@ public class RedirectView extends AbstractUrlBasedView {
return
true
;
}
@Override
public
boolean
checkResourceExists
(
Locale
locale
)
throws
Exception
{
return
true
;
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
super
.
afterPropertiesSet
();
if
(
getStatusCode
()
==
null
)
{
throw
new
IllegalArgumentException
(
"Property 'statusCode' is required"
);
}
}
}
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/RedirectViewTests.java
浏览文件 @
2633b4e9
...
...
@@ -107,7 +107,7 @@ public class RedirectViewTests {
assertFalse
(
view
.
isRemoteHost
(
"/path"
));
assertFalse
(
view
.
isRemoteHost
(
"http://url.somewhereelse.com"
));
view
.
setHosts
(
new
String
[]
{
"url.somewhere.com"
}
);
view
.
setHosts
(
"url.somewhere.com"
);
assertFalse
(
view
.
isRemoteHost
(
"http://url.somewhere.com"
));
assertFalse
(
view
.
isRemoteHost
(
"/path"
));
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录