skip to content

Why does SOAP over HTTP usually get no benefit from HTTP caches when a REST API can, and what does SOAP 1.2 offer instead?

level: middleimportance: should knowfreq 22%

answer

  1. what a cache keys on
  2. one endpoint, many operations
  3. the resource hidden in the body
  4. POST responses rarely reusable
  5. SOAP 1.2 GET for safe reads

basics

~20 s

HTTP caches reuse responses to safe GET requests identified by URI, but SOAP over HTTP typically sends every operation as a POST to one endpoint, naming the resource inside the envelope. SOAP 1.2 allows plain GET for safe retrievals.

solid answer

~50 s

A shared HTTP cache stores responses by method and target URI and reuses them for safe requests; RFC 9110 lets a `POST` response be cached only with explicit freshness and a `Content-Location` equal to the target URI, and never reuses one to answer another `POST`. SOAP's HTTP binding tunnels operations through `POST` - SOAP 1.1 defines only `POST`, and the WS-I Basic Profile forbids any other method - to one endpoint URI, with the operation and its arguments inside the envelope. A cache cannot see that two `getPolicy` calls for policy 42 are the same read. A REST API gives each resource its own URI and reads it with `GET`, which caches understand. SOAP 1.2 Part 2 lets a safe retrieval whose arguments fit in the URI go out as an HTTP `GET` with no request envelope, but that request cannot carry header blocks such as a signature.

code

http · 15 lines
http
POST /policy-service HTTP/1.1
Host: insurer.example.org
Content-Type: application/soap+xml; charset=utf-8

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
  <env:Body>
    <p:getPolicy xmlns:p="http://insurer.example.org/policy">
      <p:policyId>42</p:policyId>
    </p:getPolicy>
  </env:Body>
</env:Envelope>

GET /policies/42 HTTP/1.1
Host: insurer.example.org
Accept: application/json

go deeper

for a junior

Remember that SOAP over HTTP sends everything as POST to one endpoint, while REST reads are GET requests on resource URIs that caches understand.

for a middle

Explain what a cache keys on, why RFC 9110 almost never reuses POST responses, and the SOAP 1.2 GET convention with its no-header-block condition.

for a senior

Connect POST tunnelling to production costs: no CDN offload for reads, generic clients unable to retry safely, and per-operation metrics hidden behind one URL.

for a principal

Judge when caching actually matters for the integration - read-heavy public data versus partner write flows - before letting it drive the style decision.

## What an HTTP cache needs An HTTP cache - in a browser, a forward proxy, a CDN or a reverse proxy - saves a response and hands it to a later request that asks for **the same thing**. To know that, it looks at what HTTP exposes outside the body: - the **method**, because only safe methods such as `GET` and `HEAD` are reused freely; - the **target URI**, which is the identity of what was asked for; - freshness and validator headers such as `Cache-Control` and `ETag`. RFC 9110 is strict about `POST`: its responses "are only cacheable when they include explicit freshness information" and a `Content-Location` equal to the POST's target URI. Even then, a cached POST response can only answer a later `GET` or `HEAD` - "a POST request cannot be satisfied by a cached POST response because POST is potentially unsafe". ## What SOAP's HTTP binding does SOAP over HTTP is often called **POST tunnelling**: - The **SOAP 1.1** binding "only defines SOAP within HTTP POST requests", and the **WS-I Basic Profile** makes it a rule: a request message MUST use HTTP `POST`. - A WSDL port has **one address**, so every operation of the service is posted to the same URI. - The **operation and its arguments** sit inside the Body. The `SOAPAction` header may hint at the intent, but the WS-I Basic Profile calls it "purely a hint": the envelope carries everything that matters. The SOAP 1.2 Primer names the problem itself: for a read such as fetching an itinerary, the resource "is not identified by the target URI in the HTTP request but has to be obtained by looking within the SOAP envelope", which it calls counter to the spirit of the Web. SOAP 1.1 adds that SOAP intermediaries are not HTTP intermediaries - an HTTP proxy cannot be expected to inspect the SOAP body. ## One read, three ways | | SOAP 1.1 over HTTP | SOAP 1.2, Web-friendly retrieval | REST | |---|---|---|---| | Request line | `POST /policy-service` | `GET /policies/42` | `GET /policies/42` | | Request body | Envelope naming policy 42 | None | None | | Where the resource is named | Inside the Body | In the URI | In the URI | | Can a shared cache reuse the response? | No | Yes, if freshness allows | Yes, if freshness allows | | Can the request carry SOAP header blocks? | Yes | No | Not applicable | ## What SOAP 1.2 offers SOAP 1.2 Part 2 adds two adjuncts: 1. The **SOAP Web Method feature** lets the application choose the HTTP method; the HTTP binding supports `GET` and `POST`. 2. The **SOAP Response message exchange pattern** pairs a request that carries no envelope with a SOAP response. Its conventions in section 4.1.2 then say: when every argument is in the URI, no header blocks are needed and the retrieval is safe, use `GET` with the Response pattern, so no envelope is sent. When the operation is not a retrieval, or header blocks such as **a digital signature** must travel, use `POST` with an envelope. So the Web-friendly path exists only for unsigned, header-free reads - and every service that wants it must design its URIs for it. ## Consequences beyond caching - **Retries.** RFC 9110 lets a client repeat an idempotent request automatically after a broken connection, and says it SHOULD NOT do so for a non-idempotent method unless it knows the request is safe to repeat. Because every SOAP call is a `POST`, a generic HTTP client cannot tell a harmless read from a payment; only the contract or the application knows. - **Observability.** Access logs and route metrics show one URL for every operation, so per-operation numbers need body inspection or the `SOAPAction` hint. - **Caching that still happens.** A SOAP client or service can cache results in its own code; that is an application's or implementation's choice, invisible to and unaided by the HTTP layer. ## Where it matters Caching rarely decides a partner integration that is mostly writes. It does matter for **read-heavy, public or browser-facing** data, where a CDN in front of `GET /policies/42` absorbs most of the load - the case where a resource-oriented design wins most clearly.

  • Could a reverse proxy cache SOAP responses by hashing the request body?
    Only as a custom rule outside HTTP's caching model. RFC 9110 never lets a cached response satisfy a later POST, so the proxy would have to be told which operations are safe reads and would need to normalise XML that can differ byte for byte while meaning the same. That is an implementation's choice, not something SOAP or HTTP provides.
  • Why does a SOAP 1.2 request with a signed header block have to use POST?
    The Web-friendly GET convention in SOAP 1.2 Part 2 applies only when no SOAP header blocks are transmitted, because a GET under the SOAP Response pattern carries no request envelope at all. A signature lives in a header block, so the request needs an envelope and therefore POST, which gives up shared caching.

A library desk versus a mailroom: ask the desk for a book by its shelf number and it can hand you the copy it already fetched for the last reader. Post a sealed letter asking for the same book to the mailroom, and the clerk must open and forward every letter, because what you want is visible only inside the envelope.

saying these in an interview costs you the question

  • HTTP caches cannot store XML, which is why SOAP responses are never cached.
  • RFC 9110 forbids caching any response to a POST request.
  • SOAP has no way at all to use HTTP GET.
  • The SOAPAction header lets caches tell SOAP operations apart and reuse responses.
  • A SOAP 1.2 GET retrieval can still carry a WS-Security header.