Spring Boot - 如何在 REST 控制器 HTTP PUT 上允许 CORS
Posted
技术标签:
【中文标题】Spring Boot - 如何在 REST 控制器 HTTP PUT 上允许 CORS【英文标题】:Spring Boot - how to allow CORS on REST Controller HTTP PUT 【发布时间】:2020-05-18 18:11:57 【问题描述】:我是我的 Spring Boot REST 控制器,我能够允许 CORS 用于 HTTP POST,但由于某种原因 HTTP PUT 仍然被阻止。 我已将我的 CORS 装饰器置于控制器级别 - HTTP PUT 处理程序仍被阻止。 这是我的控制器:
package com.khoubyari.example.api.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.khoubyari.example.domain.Hotel;
import com.khoubyari.example.exception.DataFormatException;
import com.khoubyari.example.service.HotelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping(value = "/example/v1/hotels")
@Api(tags = "hotels")
//@CrossOrigin(origins = "http://localhost:4200")
@CrossOrigin( origins = "*" , allowedHeaders = "*")
public class HotelController extends AbstractRestHandler
@Autowired
private HotelService hotelService;
@RequestMapping(value = "",
method = RequestMethod.POST,
consumes = "application/json", "application/xml",
produces = "application/json", "application/xml")
@ResponseStatus(HttpStatus.CREATED)
@ApiOperation(value = "Create a hotel resource.", notes = "Returns the URL of the new resource in the Location header.")
public void createHotel(@RequestBody Hotel hotel,
HttpServletRequest request, HttpServletResponse response)
Hotel createdHotel = this.hotelService.createHotel(hotel);
response.setHeader("Location", request.getRequestURL().append("/").append(createdHotel.getId()).toString());
@RequestMapping(value = "",
method = RequestMethod.GET,
produces = "application/json", "application/xml")
@ResponseStatus(HttpStatus.OK)
@ApiOperation(value = "Get a paginated list of all hotels.", notes = "The list is paginated. You can provide a page number (default 0) and a page size (default 100)")
public
@ResponseBody
Page<Hotel> getAllHotel(@ApiParam(value = "The page number (zero-based)", required = true)
@RequestParam(value = "page", required = true, defaultValue = DEFAULT_PAGE_NUM) Integer page,
@ApiParam(value = "Tha page size", required = true)
@RequestParam(value = "size", required = true, defaultValue = DEFAULT_PAGE_SIZE) Integer size,
HttpServletRequest request, HttpServletResponse response)
return this.hotelService.getAllHotels(page, size);
@RequestMapping(value = "/id",
method = RequestMethod.GET,
produces = "application/json", "application/xml")
@ResponseStatus(HttpStatus.OK)
@ApiOperation(value = "Get a single hotel.", notes = "You have to provide a valid hotel ID.")
public
@ResponseBody
Hotel getHotel(@ApiParam(value = "The ID of the hotel.", required = true)
@PathVariable("id") Long id,
HttpServletRequest request, HttpServletResponse response) throws Exception
Hotel hotel = this.hotelService.getHotel(id);
checkResourceFound(hotel);
return hotel;
@RequestMapping(value = "/id",
method = RequestMethod.PUT,
consumes = "application/json", "application/xml",
produces = "application/json", "application/xml")
@ResponseStatus(HttpStatus.NO_CONTENT)
@ApiOperation(value = "Update a hotel resource.", notes = "You have to provide a valid hotel ID in the URL and in the payload. The ID attribute can not be updated.")
public void updateHotel(@ApiParam(value = "The ID of the existing hotel resource.", required = true)
@PathVariable("id") Long id, @RequestBody Hotel hotel,
HttpServletRequest request, HttpServletResponse response)
checkResourceFound(this.hotelService.getHotel(id));
if (id != hotel.getId()) throw new DataFormatException("ID doesn't match!");
this.hotelService.updateHotel(hotel);
//todo: @ApiImplicitParams, @ApiResponses
@RequestMapping(value = "/id",
method = RequestMethod.DELETE,
produces = "application/json", "application/xml")
@ResponseStatus(HttpStatus.NO_CONTENT)
@ApiOperation(value = "Delete a hotel resource.", notes = "You have to provide a valid hotel ID in the URL. Once deleted the resource can not be recovered.")
public void deleteHotel(@ApiParam(value = "The ID of the existing hotel resource.", required = true)
@PathVariable("id") Long id, HttpServletRequest request,
HttpServletResponse response)
checkResourceFound(this.hotelService.getHotel(id));
this.hotelService.deleteHotel(id);
为了让 HTTP PUT 处理程序允许更新,我应该更改哪些内容?
【问题讨论】:
【参考方案1】:您可能需要在 CORS 配置中明确指定允许的方法(我正在使用 Kotlin 并实现 WebMvcConfigurer
):
override fun addCorsMappings(registry: CorsRegistry)
log.info("CORS: ", origins)
registry.addMapping("/**").allowedOrigins(*origins)
.allowedMethods("GET", "POST", "PUT", "OPTIONS")
PUT默认是不允许的,见CorsConfiguration#DEFAULT_PERMIT_METHODS
:
private static final List<String> DEFAULT_PERMIT_METHODS = Collections.unmodifiableList(
Arrays.asList(HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name()));
【讨论】:
以上是关于Spring Boot - 如何在 REST 控制器 HTTP PUT 上允许 CORS的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring-boot 中不模拟服务类的情况下为 REST 控制器端点编写单元测试
如何在 Spring Boot Rest api 中创建安全登录控制器
如果它是一个 Rest 控制器,如何确保 Spring boot 自动编组一个类的对象
如何使用 power mock 对 Spring Boot Rest 控制器和异常处理程序进行单元测试