在Spring MVC 3中指定HTTP“位置”响应头的首选方法是什么?
在Spring MVC 3中指定HTTP“位置”响应头的首选方法是什么?
据我所知,Spring只会提供一个“位置”来响应重定向(“redirect:xyz”或RedirectView),但是也有一些场景应该和实体一起发送(例如,作为“201创建”的结果)。
恐怕我唯一的选择是手动指定它:
httpServletResponse.setHeader("Location", "/x/y/z");
它是否正确? 有没有更好的方法来解决这个问题?
从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); }
从版本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(); }
感谢Dieter Hubau指出这一点。
下面的例子是从春季教程:
@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()); }
请注意,以下内容将为您计算上下文路径(URI),以避免代码重复并使您的应用程序更具可移植性:
ServletUriComponentsBuilder .fromCurrentRequest().path("/{id}")
根据: http : //www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30
应该使用绝对URI:
Location = "Location" ":" absoluteURI
该URI应该正确地转义:
你的方法看起来很好,但为了保持干净,你可以把代码放到一个自定义的HandlerInterceptor
,例如只有当有一个HTTP 201的时候才会触发。
在这里看到更多的信息。
这是一个古老的问题,但是如果你想让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) = mapOf("id" to jobId) }
在这个例子中(这是写在Kotlin中,但类似于Java),基URI是/api/v1
(在类的顶部定义)。 使用MvcUriComponentsBuilder.fromMethodName
调用让Spring找出正确的完整URI。 ( MvcUriComponentsBuilder
在4.0中添加)。
这是做这件事的好方法,它符合http规范 。