[英]Springboot @DeleteMapping respond 404, but response body is empty
I have problem with @DeleteMapping
.我对
@DeleteMapping
有疑问。
Situation is like below.情况如下。
If I request to /v1/cache/{cacheEntry}
with method DELETE
,如果我使用
DELETE
方法向/v1/cache/{cacheEntry}
请求,
It respond with 404
, but body was empty.它以
404
响应,但正文为空。 no message, no spring default json 404 response message.没有消息,没有 spring 默认 json 404 响应消息。
If i request to /v1/cache/{cacheEntry}
with method POST
,如果我使用
POST
方法向/v1/cache/{cacheEntry}
请求,
It respond with 405
and body was below.它以
405
响应,身体在下方。 (This action is correct, not a bug.) (此操作是正确的,不是错误。)
If I change @DeleteMapping
to @PostMapping
, and request /v1/cache/{cacheEntry}
with method POST
, It respond success with code 200
.如果我将
@DeleteMapping
更改为@PostMapping
,并使用方法POST
请求/v1/cache/{cacheEntry}
,它会使用代码200
响应成功。
{
"timestamp": 1643348039913,
"status": 405,
"error": "Method Not Allowed",
"message": "",
"path": "/v1/cache/{cacheEntry}"
}
// Controller // Controller
@Slf4j
@RestController
@RequestMapping("/v1/cache")
@RequiredArgsConstructor
public class CacheController {
private final CacheService cacheService;
@PostMapping("/{cacheEntry}")
public CacheClearResponse clearCacheEntry(@PathVariable("cacheEntry") CacheChannels cacheEntry) {
try {
log.info("Cache entry :: " + cacheEntry);
cacheService.evictCacheEntry(cacheEntry);
return CacheClearResponse.builder()
.result(
RequestResult.builder()
.code(9200)
.message("SUCCESS")
.build()
)
.common(
Common.builder().build()
)
.date(LocalDateTime.now())
.build();
} catch (Exception e) {
e.printStackTrace();
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
return CacheClearResponse.builder()
.result(
RequestResult.builder()
.code(9999)
.message(sw.toString())
.build()
)
.common(
Common.builder().build()
)
.date(LocalDateTime.now())
.build();
}
}
}
}
// CacheService // 缓存服务
@Service
@RequiredArgsConstructor
public class CacheService {
private final CacheManager cacheManager;
public void evictCacheEntry(CacheChannels cacheEntry) {
Cache cache = cacheManager.getCache(cacheEntry.getCacheName());
if (cache != null) {
cache.clear();
}
}
public void evictCache(CacheChannels cacheEntry, String cacheKey) {
Cache cache = cacheManager.getCache(cacheEntry.getCacheName());
if (cache != null) {
cache.evict(cacheKey);
}
}
}
// Enum // 枚举
@Getter
@AllArgsConstructor
public enum CacheChannels {
CACHE_TEN_MIN(Names.CACHE_TEN_MIN, Duration.ofMinutes(10)),
CACHE_HALF_HR(Names.CACHE_HALF_HR, Duration.ofMinutes(30)),
CACHE_ONE_HR(Names.CACHE_ONE_HR, Duration.ofHours(1)),
CACHE_THREE_HR(Names.CACHE_THREE_HR, Duration.ofHours(3)),
CACHE_SIX_HR(Names.CACHE_SIX_HR, Duration.ofHours(6)),
CACHE_ONE_DAY(Names.CACHE_ONE_DAY, Duration.ofDays(1));
private final String cacheName;
private final Duration cacheTTL;
public static CacheChannels from(String value) {
return Arrays.stream(values())
.filter(cacheChannel -> cacheChannel.cacheName.equalsIgnoreCase(value))
.findAny()
.orElse(null);
}
public static class Names {
public static final String CACHE_TEN_MIN = "cache10Minutes";
public static final String CACHE_HALF_HR = "cache30Minutes";
public static final String CACHE_ONE_HR = "cache1Hour";
public static final String CACHE_THREE_HR = "cache3Hours";
public static final String CACHE_SIX_HR = "cache6Hours";
public static final String CACHE_ONE_DAY = "cache1Day";
}
}
// Converter // 转换器
@Slf4j
public class StringToCacheChannelConverter implements Converter<String, CacheChannels> {
@Override
public CacheChannels convert(String source) {
log.info("Convert Target: " + source);
return CacheChannels.from(source);
}
}
// Security Config // 安全配置
@Configuration
@EnableWebSecurity
@Order(1)
public class APISecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${spring.security.auth-token-header-name:Authorization}")
private String apiKeyHeader;
@Value("${spring.security.secret}")
private String privateApiKey;
@Override
protected void configure(HttpSecurity http) throws Exception {
APIKeyAuthFilter filter = new APIKeyAuthFilter(apiKeyHeader);
filter.setAuthenticationManager(new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String requestedApiKey = (String) authentication.getPrincipal();
if (!privateApiKey.equals(requestedApiKey)) {
throw new BadCredentialsException("The API Key was not found or not the expected value");
}
authentication.setAuthenticated(true);
return authentication;
}
});
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(filter)
.authorizeRequests()
.antMatchers("/v1/cache/**")
.authenticated();
}
}
// Filter // 筛选
@Slf4j
public class APIKeyAuthFilter extends AbstractPreAuthenticatedProcessingFilter {
private String apiKeyHeader;
public APIKeyAuthFilter(String apiKeyHeader) {
this.apiKeyHeader = apiKeyHeader;
}
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest httpServletRequest) {
log.info("Check authenticated.");
return httpServletRequest.getHeader(apiKeyHeader);
}
@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest httpServletRequest) {
return "N/A";
}
}
// Web Config // Web 配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToCacheChannelConverter());
}
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new HiddenHttpMethodFilter();
}
}
This can be expected the controller was loaded, endpoint was mapped.这可以预期 controller 已加载,端点已映射。
I tried change @DeleteMapping
to @PostMapping
and it was successfully respond against to POST
request.我尝试将
@DeleteMapping
更改为@PostMapping
,它成功响应了POST
请求。
What am I missing?我错过了什么?
I found reason why received 404 without any messages.我找到了为什么在没有任何消息的情况下收到 404 的原因。 My tomcat is on remote server.
我的 tomcat 在远程服务器上。 It configured with
security-constraint
and disable DELETE
method for all enpoints.它配置了
security-constraint
并为所有端点禁用DELETE
方法。
I just comment out it and It work properly with delete method.我只是将其注释掉,它可以与 delete 方法一起正常工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.