Java 指定HTTP的首选方式是什么;地点“;Spring MVC 3中的响应头?

Java 指定HTTP的首选方式是什么;地点“;Spring MVC 3中的响应头?,java,rest,spring-mvc,Java,Rest,Spring Mvc,在SpringMVC3中,指定HTTP“Location”响应头的首选方法是什么 据我所知,Spring将只提供一个“位置”来响应重定向(“redirect:xyz”或RedirectView),但是在某些情况下,位置应该与实体体一起发送(例如,作为“201 Created”的结果) 恐怕我唯一的选择是手动指定它: httpServletResponse.setHeader("Location", "/x/y/z"); 这是正确的吗?有没有更好的方法来解决这个问题?根据: 应使用绝对URI:

在SpringMVC3中,指定HTTP“Location”响应头的首选方法是什么

据我所知,Spring将只提供一个“位置”来响应重定向(“redirect:xyz”或RedirectView),但是在某些情况下,位置应该与实体体一起发送(例如,作为“201 Created”的结果)

恐怕我唯一的选择是手动指定它:

httpServletResponse.setHeader("Location", "/x/y/z");
这是正确的吗?有没有更好的方法来解决这个问题?

根据:

应使用绝对URI:

Location       = "Location" ":" absoluteURI  
并且应该正确转义URI


您的方法看起来不错,但是为了保持干净,您可以将代码放在自定义的
HandlerInterceptor
中,例如,只有在有HTTP 201时才会触发


有关更多信息,请参阅。

关键是使用
UriComponentsBuilder
。 有几种方法可以获得它的实例

  • MvcUriComponentsBuilder
  • UriComponentsBuilder
    作为参数注入方法
  • MvcUriComponentsBuilder
    通过这种方式,您可以获得配置为生成指向某些具有预定义参数的控制器方法的
    UriComponentsBuilder

    以下是for
    MvcUriComponentsBuilder
    的示例:

    例如,给定此控制器:

     @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);
    
    UriComponentsBuilder
    作为参数注入方法 从spring 3.1开始,可以使用
    UriComponentBuilder
    参数创建
    位置
    ,并将其设置为返回的
    响应属性
    <代码>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);
    }
    
    @RequestMapping(method=RequestMethod.POST)
    公共响应创建客户(UriComponentsBuilder b){
    UriComponents UriComponents=
    b、 路径(“/customers/{id}”).buildAndExpand(id);
    HttpHeaders=新的HttpHeaders();
    headers.setLocation(uriComponents.toUri());
    返回新的ResponseEntity(标题,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();
    }
    
    @RequestMapping(method=RequestMethod.POST)
    公共响应创建客户(UriComponentsBuilder b){
    UriComponents UriComponents=
    b、 路径(“/customers/{id}”).buildAndExpand(id);
    返回ResponseEntity.created(uriComponents.toUri()).build();
    }
    

    感谢Dieter Hubau指出这一点。

    这是一个老问题,但如果您想让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
    }
    
    @RestController
    @请求映射(“/api/v1”)
    类作业控制器{
    @后映射(“/jobs”)
    fun createJob(@RequestParam(“使用gpu”)useGPU:Boolean?):ResponseEntity{
    val headers=HttpHeaders()
    val jobId=“待定id”
    标题.位置=
    MVC组件生成器
    .fromMethodName(作业控制器::class.java,“getJob”,作业ID)
    .buildAndExpand(作业ID)
    .toUri()
    返回响应属性(标题,HttpStatus.CREATED)
    }
    @GetMapping(“/job/{jobId}”)
    fun getJob(@PathVariable jobId:String)=……//获取作业
    }
    

    在这个示例中(用Kotlin编写,但与java类似),基本URI是
    /api/v1
    (定义在类的顶部)。使用
    MvcUriComponentsBuilder.fromMethodName
    调用可以让Spring计算出正确的完整URI。(
    MvcUriComponentsBuilder
    是在4.0中添加的)。

    以下示例来自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());
    
    }
    

    这种方法有什么问题?这是一种很好的方法,它符合。headers.setLocation行上有一个语法错误。还有一个额外的结束语,并且“id”不存在。我只是想向其他遇到这个答案的人指出,这不是一个可以编译的完整方法。但是谢谢你的回答,这很有帮助。回答很好,现在你甚至可以把它缩短一点:
    returnresponseEntity.created(uriComponents.toUri()).build()是否正在注入
    UriComponentsBuilder
    ?可以是
    @Autowire
    d吗?组件没有在应答中添加端口。我总是认为你提到的文件是过时的,而不是过时的。被取代的最终结果表明,该值可以是相对的。
    @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());
    
    }
    
    ServletUriComponentsBuilder
                        .fromCurrentRequest().path("/{id}")