#886 - Polishing.

Moved section on forward header handling to the link building section of the documentation describing server side components. Switched to sentence-per-line style for the newly introduced content. Pruned a couple of details about which headers are forwarded as what exactly is supported is likely to change with the components in Spring Framework. A bit of rewording to avoid the impression that Spring HATEOAS itself is providing support for the header forwarding.

Re-ordered the server side support section before the media type one. Some polishing on the inline code examples (syntax highlighting etc.)

Original pull request: #887.
This commit is contained in:
Oliver Drotbohm
2019-03-21 17:47:56 +01:00
parent 2957c9171d
commit c4805ae03f
3 changed files with 95 additions and 116 deletions

View File

@@ -1,7 +1,5 @@
[[configuration]]
= Configuration
:code-dir: ../../../src/docs/java/org/springframework/hateoas
:resource-dir: ../../../src/docs/resources/org/springframework/hateoas
This section describes how to configure Spring HATEOAS.
@@ -15,110 +13,3 @@ To let the `RepresentationModel` subtypes be rendered according to the specifica
* By default, it enables `@EnableEntityLinks` (see <<fundamentals.obtaining-links.entity-links>>) and automatically picks up `EntityLinks` implementations and bundles them into a `DelegatingEntityLinks` instance that you can autowire.
* It automatically picks up all `RelProvider` implementations in the `ApplicationContext` and bundles them into a `DelegatingRelProvider` that you can autowire. It registers providers to consider `@Relation` on domain types as well as Spring MVC controllers. If the https://github.com/atteo/evo-inflector[EVO inflector] is on the classpath, collection `rel` values are derived by using the pluralizing algorithm implemented in the library (see <<spis.rel-provider>>).
[[configuration.forwarded-headers]]
== Forwarded header handling
Spring HATEOAS supports various https://tools.ietf.org/html/rfc7239[RFC-7239 forwarding headers]. They are most commonly used when your application is behind a proxy, behind
a load balancer, or in the cloud. The node that actually receives the web request is part of the infrastructure, and _forwards_ the request
to your application.
Your application may be running on `localhost:8080`, but to the outside world, you're expected to be at `reallycoolsite.com` (and on
web's standart port 80). By having the proxy include extra headers (which many already do), Spring HATEOAS can transform its generated
links property.
IMPORTANT: Anything that can change the root URI based on external inputs must be properly guarded. That's why, by default, forwarded
header handling is *disabled*. You MUST enable it to be operational. If you are deploying to the cloud or into a configuration where you
control the proxies and load balancers, then you'll certainly want to use this feature.
To enable forwarded header handling in a Spring MVC application running inside Spring Boot, you only need add this to your configuration:
.Registering a `ForwardedHeaderFilter`
====
[source, java, tabsize=2, indent=0]
----
include::{code-dir}/ForwardedEnabledConfig.java[tags=code-1]
----
This will create a servlet filter that processes all the `X-Forwarded-*` headers. And it will register it properly with the servlet handlers.
====
For a Spring WebFlux application, the reactive counterpart is `ForwardedHeaderTransformer`:
.Registering a `ForwardedHeaderTransformer`
====
[source, java, tabsize=2, indent=0]
----
include::{code-dir}/ForwardedEnabledConfig.java[tags=code-2]
----
This will create a function that transforms reactive web requests, processing `X-Forwarded-*` headers. And it will register it properly
with WebFlux.
====
Once enabled, you'll be able to use:
[cols='1,2', options="header"]
|===
| Header
| Description
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded[Forwarded]
| Single header that let's you apply several forwarding attributes.
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host[X-Forwarded-Host]
| Originating hostname (NOTE: Does NOT include the port).
| X-Forwarded-Port
| Originating port number
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto[X-Forwarded-Proto]
| Originating protocol (e.g. `http` or `https`).
| X-Forwarded-Prefix
| Originating prefix that was stripped off.
| X-Forwarded-Ssl
| Originating SSL status (e.g. `on`).
|===
NOTE: `X-Forwarded-*` headers aren't governed by a spec, but are instead _de facto_ standards. `Forwarded` is governed by
https://tools.ietf.org/html/rfc7239[RFC 7239], a proposed spec aimed at consolidating forwarded header handling.
You should be able to do this:
----
curl -v localhost:8080/employees \
-H 'X-Forwarded-Proto: https' \
-H 'X-Forwarded-Host: example.com' \
-H 'X-Forwarded-Port: 9001'
----
...and expect to see hypermedia rendered like this:
----
{
"_embedded": {
"employees": [
{
"id": 1,
"name": "Bilbo Baggins",
"role": "burglar",
"_links": {
"self": {
"href": "https://example.com:9001/employees/1"
},
"employees": {
"href": "https://example.com:9001/employees"
}
}
}
]
},
"_links": {
"self": {
"href": "https://example.com:9001/employees"
},
"root": {
"href": "https://example.com:9001"
}
}
}
----

View File

@@ -15,7 +15,7 @@ NOTE: Copies of this document may be made for your own use and for distribution
== Preface
include::migrate-to-1.0.adoc[leveloffset=+2]
include::fundamentals.adoc[leveloffset=+1]
include::mediatypes.adoc[leveloffset=+1]
include::server.adoc[leveloffset=+1]
include::mediatypes.adoc[leveloffset=+1]
include::configuration.adoc[leveloffset=+1]
include::client.adoc[leveloffset=+1]

View File

@@ -1,8 +1,10 @@
[[server]]
= Server-side support
:code-dir: ../../../src/docs/java/org/springframework/hateoas
:resource-dir: ../../../src/docs/resources/org/springframework/hateoas
[[server.link-builder]]
== [[fundamentals.obtaining-links]] [[fundamentals.obtaining-links.builder]] Building links
[[server.link-builder.webmvc]]
== [[fundamentals.obtaining-links]] [[fundamentals.obtaining-links.builder]] Building links in Spring MVC
Now we have the domain vocabulary in place, but the main challenge remains: how to create the actual URIs to be wrapped into `Link` instances in a less fragile way. Right now, we would have to duplicate URI strings all over the place. Doing so is brittle and unmaintainable.
@@ -72,7 +74,8 @@ return new ResponseEntity<PersonModel>(headers, HttpStatus.CREATED);
[[fundamentals.obtaining-links.builder.methods]]
==== Building Links that Point to Methods
As of version 0.4, you can even build links that point to methods or create dummy controller method invocations. The first approach is to hand a `Method` instance to the `WebMvcLinkBuilder`.
You can even build links that point to methods or create dummy controller method invocations.
The first approach is to hand a `Method` instance to the `WebMvcLinkBuilder`.
The following example shows how to do so:
====
@@ -102,14 +105,99 @@ assertThat(link.getHref()).endsWith("/people/2");
* The return type has to be capable of proxying, as we need to expose the method invocation on it.
* The parameters handed into the methods are generally neglected (except the ones referred to through `@PathVariable`, because they make up the URI).
[[server.link-builder.webmvc]]
== Building links in Spring MVC
[[server.link-builder.webflux]]
== Building links in Spring WebFlux
TODO
[[server.link-builder.forwarded-headers]]
== Forwarded header handling
https://tools.ietf.org/html/rfc7239[RFC-7239 forwarding headers] are most commonly used when your application is behind a proxy, behind a load balancer, or in the cloud.
The node that actually receives the web request is part of the infrastructure, and _forwards_ the request to your application.
Your application may be running on `localhost:8080`, but to the outside world, you're expected to be at `reallycoolsite.com` (and on web's standart port 80).
By having the proxy include extra headers (which many already do), Spring HATEOAS can generate links properly as it uses Spring Framework functionality to obtain the base URI of the original request.
IMPORTANT: Anything that can change the root URI based on external inputs must be properly guarded.
That's why, by default, forwarded header handling is *disabled*.
You MUST enable it to be operational.
If you are deploying to the cloud or into a configuration where you control the proxies and load balancers, then you'll certainly want to use this feature.
To enable forwarded header handling you need to register Spring's `ForwardedHeaderFilter` for Spring MVC (details https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#filters-forwarded-headers[here]) or `ForwardedHeaderTransformer` for Spring WebFlux (details https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-forwarded-headers[here]) in your application.
In a Spring Boot application those components can be simply declared as Spring beans as described https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-embedded-container-servlets-filters-listeners-beans[here].
.Registering a `ForwardedHeaderFilter`
====
[source, java, tabsize=2, indent=0]
----
include::{code-dir}/ForwardedEnabledConfig.java[tags=code-1]
----
====
This will create a servlet filter that processes all the `X-Forwarded-…` headers.
And it will register it properly with the servlet handlers.
For a Spring WebFlux application, the reactive counterpart is `ForwardedHeaderTransformer`:
.Registering a `ForwardedHeaderTransformer`
====
[source, java, tabsize=2, indent=0]
----
include::{code-dir}/ForwardedEnabledConfig.java[tags=code-2]
----
====
This will create a function that transforms reactive web requests, processing `X-Forwarded-…` headers.
And it will register it properly with WebFlux.
With configuration as shown above in place, a request passing `X-Forwarded-…` headers will see those reflected in the links generated:
.A request using `X-Forwarded-…` headers
====
[source, bash]
----
curl -v localhost:8080/employees \
-H 'X-Forwarded-Proto: https' \
-H 'X-Forwarded-Host: example.com' \
-H 'X-Forwarded-Port: 9001'
----
====
.The corresponding response with the links generated to consider those headers
====
[source, json]
----
{
"_embedded": {
"employees": [
{
"id": 1,
"name": "Bilbo Baggins",
"role": "burglar",
"_links": {
"self": {
"href": "https://example.com:9001/employees/1"
},
"employees": {
"href": "https://example.com:9001/employees"
}
}
}
]
},
"_links": {
"self": {
"href": "https://example.com:9001/employees"
},
"root": {
"href": "https://example.com:9001"
}
}
}
----
====
[[server.entity-links]]
== [[fundamentals.obtaining-links.entity-links]] Using the `EntityLinks` interface