java - WebMvcConfigurer addCorsMappings 暴露的标头不起作用
问题描述
我想返回一个 ETag 标头,但我的客户无法读取它,因为它没有公开。我有以下代码:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(@NonNull CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*")
.exposedHeaders("ETag");
}
@Bean
public ShallowEtagHeaderFilter shallowEtagHeaderFilter() {
return new ShallowEtagHeaderFilter();
}
}
但是客户端仍然无法读取 ETag。唯一有效的是以下内容:
@ApiResponses({
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 500, message = "System Error")
})
@ApiOperation(value = "returns the meals", response = MealDTO.class, responseContainer = "List", produces = MediaType.APPLICATION_JSON_VALUE)
@GetMapping("/meal")
public List<MealDTO> getMeals(
@ApiParam(name = "page", type = "Integer", value = "Number of the page", example = "2")
@RequestParam(required = false) Integer page,
@ApiParam(name = "size", type = "Integer", value = "The size of one page", example = "5")
@RequestParam(required = false) Integer size,
@ApiParam(name = "sortBy", type = "String", value = "sort criteria", example = "name.asc,price.desc")
@RequestParam(required = false) String sortBy,
@ApiParam(name = "userId", type = "long", value = "ID of the User", example = "-1")
@PathVariable Long userId,
HttpServletResponse response
) {
log.debug("Entered class = MealController & method = getMeals");
response.setHeader("Access-Control-Expose-Headers", "ETag");
return this.mealService.getMealsByUserId(page, size, sortBy, userId);
}
手动设置每个端点的公开标头。这不是 Cors Mapping 应该做的吗?ExposedHeaders 根本不适合我。
更新:
从下面的评论中我看到它可能与 WebSecurityConfigurerAdapter 有关,我还补充说:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
public WebSecurityConfig(@Qualifier("userServiceImpl") UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors()
.and()
.addFilter(new AuthenticationFilter(authenticationManager()))
.addFilter(new AuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// http.headers().cacheControl().disable();
}
//region Beans
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
//endregion
}
更新 2:
显示我如何从客户那里拨打电话:
export const getMealByIdApi: (mealId: number, etag: string | null) => Promise<Meal | void> = (mealId, etag) => {
let _config = config;
if (etag) {
_config.headers['If-None-Match'] = etag;
}
return axiosInstance
.get<Meal>(`/meal/${mealId}`, _config)
.then(response => {
log(`[getMealByIdApi] [${response.status}] Successful API call for meal with id ${mealId}.`);
const result: Meal = response.data;
result.etag = response.headers['etag'];
return result;
})
.catch(err => {
if (err.response.status === 304) {
log(`[getMealByIdApi] [304] Successful API call for meal with id ${mealId}.`);
return;
}
throw err;
});
}
如果我没有在端点中明确指定,我在标题中没有 etag: response.setHeader("Access-Control-Expose-Headers", "ETag");
解决方案
根据Axios 获取响应头字段。我们需要将“ETag”添加到“Access-Control-Expose-Headers”中,这样我们就可以访问response.headers['etag']
. 由于您已经ShallowEtagHeaderFilter
在addCorsMappings
. 应将“ETag”添加到 CORS 请求的响应标头“Access-Control-Expose-Headers”中。
为确保您请求的是 CORS,您可以调试DefaultCorsProcessor#processRequest
方法,并检查是否CorsUtils.isCorsRequest(request)
返回 true。
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,
HttpServletResponse response) throws IOException {
response.addHeader(HttpHeaders.VARY, HttpHeaders.ORIGIN);
response.addHeader(HttpHeaders.VARY, HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD);
response.addHeader(HttpHeaders.VARY, HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
if (!CorsUtils.isCorsRequest(request)) {
return true; // will not add response header if not CORS
}
...add response header
如果返回 false,您可以从CorsUtils#isCorsRequest
描述中检查 CORS 请求的要求:
如果请求是有效的 CORS,则返回 true,方法是检查 Origin 标头是否存在并确保来源不同。
推荐阅读
- node.js - 如何在 MERN 中使用 multer 上传多个文件输入?
- java - Jhipster 注册中心尝试注册自己
- google-meet - Google Meet:获取会议的当前活跃成员
- svg - 在 SVG 中定位文本元素的字体大小和 x/y 百分比之间有什么关系?
- javascript - Firebase Realtime Database equalTo query for child in increasing keys
- haskell - 使用 IntelliJ-Haskell 插件在 IntelliJ 中创建 Haskell 项目时出错
- docker - 在 AWS Lambda 容器镜像中使用 Gradle 的 shadowJar
- java - Reactor onErrorContinue 运算符是否让原始序列继续?
- powershell - 使用 PowerShell 从证书中检索 KeySpec 值
- c - 我的 libsnark 合规性谓词程序有什么问题?