英文:
Spring Boot Duplicated Endpoints
问题
第一件需要澄清的事情可能是标题可能不太具体,但我不知道如何更好地表达,因为我不理解我遇到的问题。
一点背景:
我有一个使用JWT身份验证和安装了Swagger的Spring Boot应用程序。
我作为示例使用的控制器具有以下内容。
@RestController
@RequestMapping("/api/v1")
@CrossOrigin(origins = "*")
@Api(value = "Operations Dummy")
public class DummyController {
@Autowired
IDummyService _IDummyService;
@ApiOperation(value = "Get All Dummy")
@GetMapping("/dummy")
public ResponseEntity<ResultList<DummyDTO>> getAllDummy() {
return _IDummyService.getAll();
}
}
像这样的控制器有好几个,都类似。
应用程序的正确运行方式是调用端点 GET http://localhost:8080/api/v1/dummy
响应将类似于以下内容:
{
"data": [
{
"id": 0,
"name": "test"
},
{
"id": 1,
"name": "dummy"
}
],
"metadata": {
"count": 0
}
}
问题是,一些端点可以从根目录访问,如下所示:GET http://localhost:8080/dummy
它们会产生不同的响应,但仍然显示数据
{
"_embedded" : {
"dummy" : [ {
"id" : "0",
"name" : "test",
"_links" : {
"self" : {
"href" : "http://localhost:8080A/dummy/0"
}
},{
"id" : "1",
"name" : "dummy",
"_links" : {
"self" : {
"href" : "http://localhost:8080/dummy/1"
}
} ]
},
"_links" : {
"first" : {
"href" : "http://localhost:8080/dummy"
},
.
.
.
},
"page" : {
"size" : 20,
"totalElements" : 32,
"totalPages" : 2,
"number" : 0
}
}
有关更多信息,这是配置文件的副本:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().
authorizeRequests()
.antMatchers("/api/v1/users/auth").permitAll()
.antMatchers("/error",
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/**",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers("/api/v1/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
正如我所说,并非每个控制器都会出现这种情况,实际上,当我意识到这个问题时,我删除了虚拟控制器并重新编译了项目,但仍然可以通过/dummy获取信息,而不是通过/api/v1/dummy
至于日志,在调用/dummy时会产生以下日志:
o.s.web.servlet.DispatcherServlet : GET "/dummy", parameters={}
m.m.a.RequestResponseBodyMethodProcessor : Using 'application/hal+json;q=0.8', ...
m.m.a.RequestResponseBodyMethodProcessor : Writing [PagedResource { content:
o.s.web.servlet.DispatcherServlet : Completed 200 OK
而对于对/api/v1/dummy的调用,则是:
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.es.controller.DummyController#getAllDummy()
o.s.web.servlet.DispatcherServlet : GET "/api/v1/dummy", parameters={}
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.es.controller.DummyController#getAllDummy()
o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [com.example.es.util.ResultList@19771362]
o.s.web.servlet.DispatcherServlet : Completed 200 OK
更新:
我在application.properties文件中添加了以下行,似乎现在确实返回404,但我不确定这是否会影响操作。
spring.data.rest.detection-strategy=annotated
英文:
The first thing to clarify is that perhaps the title is not very concrete but I do not know how to express it better because I do not understand the problem I have.
A little bit of context:
I have a Spring Boot application with JWT authentication and Swagger installed.
The controller I am using as an example has the following content.
@RestController
@RequestMapping("/api/v1")
@CrossOrigin(origins = "*")
@Api(value = "Operations Dummy")
public class DummyController {
@Autowired
IDummyService _IDummyService;
@ApiOperation(value = "Get All Dummy")
@GetMapping("/dummy")
public ResponseEntity<ResultList<DummyDTO>> getAllDummy() {
return _IDummyService.getAll();
}
}
Like this controller there are several, all similar.
The correct functioning of the application would be to call the endpoint GET http://localhost:8080/api/v1/dummy
The response would be similar to the following:
{
"data": [
{
"id": 0,
"name": "test"
},
{
"id": 1,
"name": "dummy"
}
],
"metadata": {
"count": 0
}
}
The problem is that some of the endpoints are accessible from the root, as follows: GET http://localhost:8080/dummy
And they produce a different response, but still show the data
{
"_embedded" : {
"dummy" : [ {
"id" : "0",
"name" : "test",
"_links" : {
"self" : {
"href" : "http://localhost:8080A/dummy/0"
}
},{
"id" : "1",
"name" : "dummy",
"_links" : {
"self" : {
"href" : "http://localhost:8080/dummy/1"
}
} ]
},
"_links" : {
"first" : {
"href" : "http://localhost:8080/dummy"
},
.
.
.
},
"page" : {
"size" : 20,
"totalElements" : 32,
"totalPages" : 2,
"number" : 0
}
}
For more information this is a copy of the configuration file:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().
authorizeRequests()
.antMatchers("/api/v1/users/auth").permitAll()
.antMatchers("/error",
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/**",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers("/api/v1/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
As I said, not with every controller this happens, in fact, when I realized that this problem was happening, I deleted the dummy controller and compiled the project again, and it was still possible to get the information through /dummy and not through /api/v1/dummy
As for the logs, when we call /dummy the following log is produced:
o.s.web.servlet.DispatcherServlet : GET "/dummy", parameters={}
m.m.a.RequestResponseBodyMethodProcessor : Using 'application/hal+json;q=0.8', ...
m.m.a.RequestResponseBodyMethodProcessor : Writing [PagedResource { content:
o.s.web.servlet.DispatcherServlet : Completed 200 OK
while for the call to /api/v1/dummy it is:
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.es.controller.DummyController#getAllDummy()
o.s.web.servlet.DispatcherServlet : GET "/api/v1/dummy", parameters={}
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.es.controller.DummyController#getAllDummy()
o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [com.example.es.util.ResultList@19771362]
o.s.web.servlet.DispatcherServlet : Completed 200 OK
Update:
I have added the following line in the application.properties file and it seems that now it does return 404, but I am not sure if this can affect the operation
spring.data.rest.detection-strategy=annotated
答案1
得分: 1
因为您正在使用 spring-data-rest starter
,它在幕后执行了许多操作。
比如 -
-
使用HAL作为媒体类型,为您的领域模型公开了一个可发现的REST API。
-
公开代表您的模型的集合、项和关联资源。
基本上,您的所有存储库和集合都会以API的形式被公开。
默认情况下,Spring Data REST会在根URI('/')上提供REST资源。这就是为什么您能够在 http://localhost:8080/dummy
上获得响应。
您可以通过在 application.properties
中设置 spring.data.rest.basePath
来更改此根路径。
因此,如果您将其设置为 spring.data.rest.basePath=/pablo
,那么您将无法在 http://localhost:8080/dummy
上获得响应数据。而是会在 http://localhost:8080/pablo/dummy
上获得响应。
一些有用的文档:
https://docs.spring.io/spring-data/rest/docs/3.3.4.RELEASE/reference/html/#reference
英文:
Since you are using spring-data-rest starter
it does a lot of things behind the scenes.
Such as -
-
Exposes a discoverable REST API for your domain model using HAL as media type.
-
Exposes collection, item and association resources representing your model.
Basically all your repositiories and collections are exposed as APIs.
By default, Spring Data REST serves up REST resources at the root URI, '/'. That is why you are able to get response for http://localhost:8080/dummy
.
You can this root by setting spring.data.rest.basePath
in application.properties.
So if you set it to spring.data.rest.basePath=/pablo
then you won't get response data for http://localhost:8080/dummy
. Instead you will get response on http://localhost:8080/pablo/dummy
Some useful docs :-
https://docs.spring.io/spring-data/rest/docs/3.3.4.RELEASE/reference/html/#reference
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论