Java 在 Spring MVC 3 中指定 HTTP“位置”响应头的首选方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3318912/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the preferred way to specify an HTTP "Location" Response Header in Spring MVC 3?
提问by Brian Kent
What is the preferred way to specify an HTTP "Location" Response Header in Spring MVC 3?
在 Spring MVC 3 中指定 HTTP“位置”响应头的首选方法是什么?
As far as I can tell, Spring will only provide a "Location" in response to a redirect ("redirect:xyz" or RedirectView), however there are scenarios where a Location should be sent along with the entity body (ex, as a result of a "201 Created").
据我所知,Spring 只会提供一个“位置”来响应重定向(“redirect:xyz”或 RedirectView),但是在某些情况下,位置应该与实体主体一起发送(例如,作为“201 Created”的结果)。
I'm afraid my only option is manually specifying it:
恐怕我唯一的选择是手动指定它:
httpServletResponse.setHeader("Location", "/x/y/z");
Is this correct? Is there a better way to tackle this problem?
这样对吗?有没有更好的方法来解决这个问题?
采纳答案by Roman Konoval
The key point is to use UriComponentsBuilder
.
There are several ways how you can get the instance of it
关键是使用UriComponentsBuilder
. 有几种方法可以获取它的实例
- preconfigured
UriComponentsBuilder
fromMvcUriComponentsBuilder
UriComponentsBuilder
injected as parameter to method
- 预配置
UriComponentsBuilder
自MvcUriComponentsBuilder
UriComponentsBuilder
作为参数注入方法
Preconfigured UriComponentsBuilder
from MvcUriComponentsBuilder
预配置UriComponentsBuilder
自MvcUriComponentsBuilder
This way you can get UriComponentsBuilder
that is configured to produce URI
that points to some controller methods with predefined parameters.
通过这种方式,您可以将UriComponentsBuilder
其配置为生成URI
指向具有预定义参数的某些控制器方法。
Here is example from the javadocfor MvcUriComponentsBuilder
:
下面是例如,从的javadoc为MvcUriComponentsBuilder
:
For example, given this controller:
例如,给定这个控制器:
@RequestMapping("/people/{id}/addresses")
class AddressController {
@RequestMapping("/{country}")
public HttpEntity<Void> getAddressesForCountry(@PathVariable String country) { ... }
@RequestMapping(value="/", method=RequestMethod.POST)
public void addAddress(Address address) { ... }
}
A UriComponentsBuilder can be created:
// Inline style with static import of "MvcUriComponentsBuilder.on"
MvcUriComponentsBuilder.fromMethodCall(
on(AddressController.class).getAddressesForCountry("US")).buildAndExpand(1);
Another options which sometimes may be preferable is to specify controller method by name:
有时可能更可取的另一个选项是按名称指定控制器方法:
UriComponents uriComponents = MvcUriComponentsBuilder.fromMethodName(
AddressController.class, "getAddressesForCountry", "US").buildAndExpand(1);
URI nextUri = uriComponents.toUri();
UriComponentsBuilder
injected as parameter to method
UriComponentsBuilder
作为参数注入方法
As of spring 3.1 Location
can be crafted using UriComponentBuilder
parameter and set it to the returned ResponseEntity
. UriComponentBuilder
is aware of the context and manipulates with relative paths:
从 spring 3.1 开始,Location
可以使用UriComponentBuilder
参数制作并将其设置为返回的ResponseEntity
. UriComponentBuilder
了解上下文并使用相对路径进行操作:
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> createCustomer(UriComponentsBuilder b) {
UriComponents uriComponents =
b.path("/customers/{id}").buildAndExpand(id);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(uriComponents.toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
Since version 4.1 you can make it even shorter
从 4.1 版开始,你可以让它更短
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> createCustomer(UriComponentsBuilder b) {
UriComponents uriComponents =
b.path("/customers/{id}").buildAndExpand(id);
return ResponseEntity.created(uriComponents.toUri()).build();
}
Thanks to Dieter Hubau to pointing this out.
感谢 Dieter Hubau 指出这一点。
回答by tszming
According to: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30
根据:http: //www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30
Absolute URI should be used:
应该使用绝对 URI:
Location = "Location" ":" absoluteURI
And the URIshould be escaped properly:
而URI应该正确转义:
回答by earldouglas
回答by yan
It's an old question but here is what you can do if you want to let Spring really build the URI for you.
这是一个老问题,但如果您想让 Spring 真正为您构建 URI,您可以这样做。
@RestController
@RequestMapping("/api/v1")
class JobsController {
@PostMapping("/jobs")
fun createJob(@RequestParam("use-gpu") useGPU: Boolean?): ResponseEntity<Unit> {
val headers = HttpHeaders()
val jobId = "TBD id"
headers.location =
MvcUriComponentsBuilder
.fromMethodName(JobsController::class.java, "getJob", jobId)
.buildAndExpand(jobId)
.toUri()
return ResponseEntity(headers, HttpStatus.CREATED)
}
@GetMapping("/job/{jobId}")
fun getJob(@PathVariable jobId: String) = ... // fetch job
}
In this example (which is written in Kotlin but similar for java), the base URI is /api/v1
(defined at the top of the class). Using MvcUriComponentsBuilder.fromMethodName
call lets Spring figure out the proper full URI. (MvcUriComponentsBuilder
was added in 4.0).
在这个例子中(它是用 Kotlin 编写的,但类似于 java),基本 URI 是/api/v1
(在类的顶部定义)。使用MvcUriComponentsBuilder.fromMethodName
call 让 Spring 找出正确的完整 URI。(MvcUriComponentsBuilder
在 4.0 中添加)。
回答by Agustí Sánchez
The following example is from spring tutorial:
以下示例来自 spring 教程:
@RequestMapping(method = RequestMethod.POST)
ResponseEntity<?> add(@PathVariable String userId, @RequestBody Bookmark input) {
this.validateUser(userId);
return this.accountRepository
.findByUsername(userId)
.map(account -> {
Bookmark result = bookmarkRepository.save(new Bookmark(account,
input.uri, input.description));
URI location = ServletUriComponentsBuilder
.fromCurrentRequest().path("/{id}")
.buildAndExpand(result.getId()).toUri();
return ResponseEntity.created(location).build();
})
.orElse(ResponseEntity.noContent().build());
}
Take note that the following will compute the context path (URI) for you avoiding code duplication and making your application more portable:
请注意,以下内容将为您计算上下文路径 (URI),以避免代码重复并使您的应用程序更具可移植性:
ServletUriComponentsBuilder
.fromCurrentRequest().path("/{id}")