我试图使用OpenFeign和ResourceAssembler将URI添加到位于其他微服务中的资源,同时保留原始请求中的主机名。
当对另一个微服务中的HATEOAS资源发出REST请求时,resource.getId()方法将返回一个链接,其中主机名是Docker容器哈希,而不是用于发出请求的原始主机名。
@RestController
@RequestMapping("/bulletins")
public class BulletinController {
// Autowired dependencies
@GetMapping(produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<PagedResources<BulletinResource>> getBulletins(Pageable pageable) {
Page<Bulletin> bulletins = bulletinRepository.findAll(pageable);
return ResponseEntity.ok(pagedResourceAssembler.toResource(bulletins, bulletinResourceAssembler));
}
}
@Component
public class BulletinResourceAssembler extends ResourceAssemblerSupport<Bulletin, BulletinResource> {
private final AdministrationService administrationService;
@Autowired
public BulletinResourceAssembler(AdministrationService administrationService) {
super(BulletinController.class, BulletinResource.class);
this.administrationService = administrationService;
}
@Override
public BulletinResource toResource(Bulletin entity) {
Resource<Site> siteRessource = administrationService.getSiteBySiteCode(entity.getSiteCode());
\\ Set other fields ...
bulletinRessource.add(siteRessource.getId().withRel("site"));
return bulletinRessource;
}
}
@FeignClient(name = "${feign.administration.serviceId}", path = "/api")
public interface AdministrationService {
@GetMapping(value = "/sites/{siteCode}")
Resource<Site> getSiteBySiteCode(@PathVariable("siteCode") String siteCode);
}
@Data
public class BulletinResource extends ResourceSupport {
// fields
}
预期结果
卷曲http://myhost/api/bulletins
{
"_embedded" : {
"bulletinResources" : [ {
"entityId" : 1,
"_links" : {
"self" : {
"href" : "http://myhost/api/bulletins/1"
},
"site" : {
"href" : "http://myhost/api/sites/000"
}
}
} ]
},
[...]
}
实际结果
卷曲http://myhost/api/bulletins
{
"_embedded" : {
"bulletinResources" : [ {
"entityId" : 1,
"_links" : {
"self" : {
"href" : "http://myhost/api/bulletins/1"
},
"site" : {
"href" : "http://b4dc1a02586c:8080/api/sites/000"
}
}
} ]
},
[...]
}
请注意,站点href为b4dc1a02586c,这是Docker容器ID。
答案 0 :(得分:0)
解决方案是手动为FeignClient定义一个RequestInterceptor,并手动添加X-Forwarded-Host标头,并在向其发出请求的服务中定义ForwardedHeaderFilter bean。
public class ForwardHostRequestInterceptor implements RequestInterceptor {
private static final String HOST_HEADER = "Host";
private static final String X_FORWARDED_HOST = "X-Forwarded-Host";
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
if (requestAttributes == null) {
return;
}
HttpServletRequest request = requestAttributes.getRequest();
String host = request.getHeader(X_FORWARDED_HOST);
if (host == null) {
host = request.getHeader(HOST_HEADER);
}
requestTemplate.header(X_FORWARDED_HOST, host);
}
}
生产者方面还需要根据有关讨论进行修改
https://github.com/spring-projects/spring-hateoas/issues/862
指的是以下文档
https://docs.spring.io/spring-hateoas/docs/current-SNAPSHOT/reference/html/#server.link-builder.forwarded-headers
指出要添加以下bean以便使用转发头。
@Bean
ForwardedHeaderFilter forwardedHeaderFilter() {
return new ForwardedHeaderFilter();
}