HTTP로 POST 메소드를 캐시 할 수 있습니까?


152

매우 간단한 캐싱 의미론을 사용하면 매개 변수가 동일하고 URL이 동일하면 적중합니다. 가능합니까? 추천?

답변:


93

섹션 9.5 (POST) 의 해당 RFC 2616 을 사용하면 적절한 헤더를 사용하는 경우 POST 메시지 에 대한 응답 을 캐싱 할 수 있습니다.

응답에 적절한 Cache-Control 또는 Expires 헤더 필드가 포함되어 있지 않으면이 방법에 대한 응답을 캐시 할 수 없습니다. 그러나 303 (기타 참조) 응답을 사용하여 사용자 에이전트가 캐시 가능한 자원을 검색하도록 지시 할 수 있습니다.

동일한 RFC는 섹션 13 (HTTP에서 캐시)에서 명시 적으로 POST 요청 후 캐시가 해당 엔티티를 무효화해야 함을 명시합니다 .

일부 HTTP 메소드는 캐시가 엔티티를 무효화하도록해야합니다. 이는 Request-URI 또는 ​​Location 또는 Content-Location 헤더 (있는 경우)에 의해 참조되는 엔티티입니다. 이러한 방법은 다음과 같습니다.

  - PUT
  - DELETE
  - POST

이러한 사양이 어떻게 의미있는 캐싱을 허용 할 수 있는지는 확실하지 않습니다.

이것은 또한 RFC 2616을 폐지하는 RFC 7231 (4.3.3 절) 에 반영되고 더 명확 해졌다 .

POST 요청에 대한 응답은
명시 적 최신 정보가 포함 된 경우에만 캐시 할 수 있습니다 ([RFC7234]의 4.2.1 절 참조).
그러나 POST 캐싱은 널리 구현되지 않았습니다. 오리진 서버가 클라이언트가 나중에 GET에 의해 재사용 될 수있는 방식으로 POST 결과를 캐시 할 수 있기를 원하는 경우, 오리진 서버는 결과와 Content-Location을 포함하는 200 (OK) 응답을 보낼 수 있습니다. POST의 유효 요청 URI와 동일한 값을 가진 헤더 필드 (3.1.4.2 단원)

이에 따라, 캐시 된 POST의 결과 (이 능력이 서버에 의해 표시되는 경우)는 동일한 URI에 대한 GET 요청의 결과로서 후속 적으로 사용될 수있다.


1
이 섹션은 원본 서버가 아닌 중간 캐시 (캐싱 프록시 서버와 같은)에 적용됩니다.
David Z

2
오리진 서버는 HTTP와 POST 요청을 처리하는 애플리케이션 사이의 브로커입니다. 응용 프로그램이 HTTP 경계를 넘어서서 원하는대로 할 수 있습니다. 캐싱이 특정 POST 요청에 대해 의미가있는 경우 OS가 디스크 요청을 캐시 할 수있는 한 캐시를 자유롭게 수행 할 수 있습니다.
Diomidis Spinellis 2016 년

2
캐싱 POST 요청이 HTTP가 아니라는 Diomidis의 설명이 잘못되었습니다. 자세한 내용은 reBoot의 답변을 참조하십시오. 맨 위에 오답을 표시하는 것은 큰 도움이되지 않지만 민주주의가 작동하는 방식입니다. reBoot에 동의하면 답변을 수정하면 좋을 것입니다.
Eugene Beresovsky

2
Eugene은 a) POST가 캐시 된 엔터티를 무효화 (섹션 13.10)하여 예를 들어 후속 GET이 fersh 사본을 가져와야하며 b) POST의 응답을 캐시 할 수 있도록 (9.5 섹션) 후속 POST에서 동일한 응답을받을 수 있습니까?
Diomidis Spinellis

3
이것은 HTTPbis에 의해 명확 해지고 있습니다; 요약 은 mnot.net/blog/2012/09/24/caching_POST 를 참조하십시오 .
Mark Nottingham

68

RFC 2616 섹션 9.5에 따르면 :

"응답에 적절한 Cache-Control 또는 Expires 헤더 필드가 포함되어 있지 않는 한 POST 방법에 대한 응답은 캐시 할 수 없습니다."

예, POST 요청 응답을 적절한 헤더와 함께 도착한 경우에만 캐시 할 수 있습니다. 대부분의 경우 응답을 캐시하고 싶지 않습니다. 그러나 서버에 데이터를 저장하지 않는 경우와 같은 일부 경우에는 전적으로 적합합니다.

그러나 현재 Firefox 3.0.10을 포함한 많은 브라우저는 헤더에 관계없이 POST 응답을 캐시하지 않습니다. IE는 이런 점에서보다 현명하게 행동합니다.

이제 RFC 2616 S에 대한 혼란을 해결하고 싶습니다. 13.10. URI의 POST 메소드는 여기에 언급 된대로 "캐싱 할 자원을 무효화"하지 않습니다. 캐시 제어 헤더가 더 오래 지속되는 신선도를 표시하더라도 이전에 캐시 된 해당 버전의 URI를 무효로 만듭니다.


2
헤더 문제를 설명하고 13.10에 관한 잘못된 설명을 수정 해 주셔서 감사합니다. 그 잘못된 대답을 놀라게해서 너무 많은 투표를 받았습니다.
유진 Beresovsky

3
"캐싱을위한 리소스 무효화"와 "캐시 된 버전의 URI를 무효화"의 차이점은 무엇입니까? 서버가 POST 응답을 캐시 할 수 있지만 클라이언트가 그렇지 않을 수 있다고 말하고 있습니까?
길리

1
"URI 캐시의 캐시 된 버전 만들기"는 요청 GET및 동일한 URI를 사용하는 경우에 적용됩니다 POST. 클라이언트와 서버 사이에있는 GET /foo캐시 인 경우 응답 을보고 캐시합니다. 당신이 볼 다음으로 POST /foo당신은하는 요구 에서 캐시 된 응답을 무효화 GET /foo짝수 경우 POST응답이 어떤 캐시 제어 헤더를 포함하지 않는 그들은 같은 URI 때문에 따라서 다음은, GET /foo원래의 헤더는 캐시가 계속 될 것임을 시사 경우에도 재 검증해야한다 라이브 ( POST /foo요청을 보지 못한 경우)
Stephen Connolly

But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.. 그런 POST API의 요점은 무엇입니까?
Siddhartha

33

사무용 겉옷:

기본적으로 POST는 dem 등원 작업이 아닙니다 . 따라서 캐싱에 사용할 수 없습니다. GET은 dem 등원 작업이어야하므로 캐싱에 일반적으로 사용됩니다.

HTTP 1.1 RFC 2616 S. 9.1 섹션 9.1을 참조하십시오 .

GET 메소드의 의미 이외의 것 :

POST 메소드 자체는 의미 적으로 자원에 무언가를 게시하기위한 것입니다. POST를 캐시 할 수 없습니다. 한 번 대 두 번 대 세 번 작업을 수행하면 매번 서버 리소스가 변경되기 때문입니다. 각 요청은 중요하며 서버로 전달되어야합니다.

PUT 메소드 자체는 의미 상 자원을 넣거나 작성하기위한 것입니다. dem 등원 작업이지만 그 동안 DELETE가 발생할 수 있으므로 캐싱에 사용되지 않습니다.

DELETE 메서드 자체는 의미 상 리소스를 삭제하기위한 것입니다. dem 등원 작업이지만 그 동안 PUT이 발생할 수 있기 때문에 캐싱에 사용되지 않습니다.

클라이언트 측 캐싱과 관련하여 :

웹 브라우저는 이전 POST 작업의 응답이 있더라도 항상 요청을 전달합니다. 예를 들어 며칠 간격으로 gmail로 이메일을 보낼 수 있습니다. 제목과 본문은 같을 수 있지만 두 이메일을 모두 보내야합니다.

프록시 캐싱과 관련하여 :

메시지를 서버로 전달하는 프록시 HTTP 서버는 GET 또는 HEAD 요청 외에는 아무것도 캐시하지 않습니다.

서버 캐싱과 관련하여 :

기본적으로 서버는 캐시 확인을 통해 POST 요청을 자동으로 처리하지 않습니다. 물론 POST 요청을 응용 프로그램이나 추가 기능으로 보낼 수 있으며 매개 변수가 같을 때 읽은 자체 캐시를 가질 수 있습니다.

자원 무효화 :

당좌 2616 S. 13.10 HTTP 1.1 RFC를 POST 메서드 캐싱을위한 리소스를 무효화해야한다고 쇼.


9
"기본적으로 POST는 idempotent 작업이 아닙니다. 따라서 캐싱에 사용할 수 없습니다." 그건 틀렸고, 실제로 이해가되지 않습니다. 자세한 내용은 reBoot의 답변을 참조하십시오. 불행히도, 나는 아직 공감할 수 없다. 그렇지 않으면 나는 가질 것이다.
Eugene Beresovsky

1
유진 : "is not"을 "not not"으로 변경했습니다.
Brian R. Bondy

1
고마워 Brian, 그게 더 좋은 소리. "POST not idemp.-> ca n't cached"에 대한 나의 문제는 그랬지만-작업이 dem 등성이 아니더라도 캐시 할 수 없다는 의미는 아니지만 충분히 명확하게하지 못했습니다. 문제는 데이터를 제공하고 의미를 알고있는 서버의 관점에서 보는 것입니까, 수신 측 (캐싱 프록시 등 또는 클라이언트인지)에서 보는 것입니다. . 그것이 클라이언트 / 프록시 POV라면, 나는 당신의 게시물에 전적으로 동의합니다. 서버 POV 인 경우 서버가 "클라이언트 캐시 가능"이라고 말하면 클라이언트가 캐시 할 수있는 것보다.
Eugene Beresovsky 1

1
유진 : 메시지를 목록에 게시하는 경우와 같이 한 번 또는 5 번 호출되는지에 차이가있는 경우 해당 호출이 서버에 5 번 올바르게 도달하기를 원합니까? 그리고 캐시하지 않으려 고 서버에 제대로 충돌하지 않습니까? 중요한 부작용이 있기 때문입니다.
브라이언 R. 본디

[계속] 그러나 서버가 실제로 캐시 허용 헤더를 보내야하는지에 대한 생각은하지 않았습니다. 그래도 말이 되네요. [귀하의 답변을 보았습니다] : 동의합니다. 제 생각에는 서버가 dem 등성 (Idempotency)의 경우에만 캐시 가능성을 표시해야하며, 특히 X-HTTP-Method-Override의 필요성을 고려할 때 POST 일 수도 있습니다. 어떤 경우.
Eugene Beresovsky 1

6

POST 응답을 캐시하는 경우 웹 애플리케이션의 지시에 따라야합니다. 이는 "응답에 적절한 Cache-Control 또는 Expires 헤더 필드가 포함되어 있지 않으면이 방법에 대한 응답을 캐싱 할 수 없습니다"라는 의미입니다.

POST의 결과가 dem 등원인지 아닌지를 아는 응용 프로그램이 필요하고 적절한 캐시 제어 헤더를 첨부할지 여부를 결정한다고 안전하게 가정 할 수 있습니다. 캐싱이 허용되는 헤더가있는 경우 애플리케이션은 실제로 POST가 슈퍼 GET임을 알려줍니다. POST 사용은 dem 등원 (imdempotent) 작업을 수행하는 데 필요한 불필요하고 관련이없는 (URI를 캐시 키로 사용하는) 데이터로 인해 필요했습니다.

이 가정에 따라 다음과 같은 GET이 캐시에서 제공 될 수 있습니다.

캐싱 가능 및 캐싱 불가능 POST 응답을 구별하기 위해 필요하고 올바른 헤더를 첨부하지 못한 응용 프로그램은 유효하지 않은 캐싱 결과에 결함이 있습니다.

즉, 캐시에 도달하는 각 POST는 조건부 헤더를 사용하는 유효성 검사가 필요합니다. 이는 오브젝트의 수명이 만료 될 때까지 POST 결과가 요청에 대한 응답에 반영되지 않도록 캐시 컨텐츠를 새로 고치기 위해 필요합니다.


4

Mark Nottingham은 POST 응답을 캐시 할 수있을 때 분석했습니다. 캐싱을 활용하려는 후속 요청은 GET 또는 HEAD 요청이어야합니다. http 의미론 참조

POST는 100에서 99 번의 식별 된 상태를 다루지 않습니다. 그러나 한 가지 경우가 있습니다. 서버가 요청 URI와 동일한 Content-Location 헤더를 설정하여이 POST 응답이 URI의 표현이라고 말하는 데 방해가되는 경우. 이런 경우 POST 응답은 동일한 URI에 대한 GET 응답과 같습니다. 캐시하고 재사용 할 수 있지만 향후 GET 요청에만 사용할 수 있습니다.

https://www.mnot.net/blog/2012/09/24/caching_POST .


4

게시 요청을 캐시하고 해당 질문에 대한 답변을 조사 할 수 있는지 궁금하다면 성공하지 못할 것입니다. "캐시 게시 요청"을 검색 할 때 첫 번째 결과는이 StackOverflow 질문입니다.

캐싱의 작동 방식, RFC에 따른 캐싱 작동 방식, RFC에 따른 캐싱 작동 방식 및 실제로 캐싱 작동 방식이 혼재되어 있습니다. RFC부터 시작하여 브라우저가 실제로 어떻게 작동하는지 시연 한 다음 CDN, GraphQL 및 기타 관심 영역에 대해 이야기하겠습니다.

RFC 2616

RFC에 따라 POST 요청은 캐시를 무효화해야합니다.

13.10 Invalidation After Updates or Deletions

..

Some HTTP methods MUST cause a cache to invalidate an entity. This is
either the entity referred to by the Request-URI, or by the Location
or Content-Location headers (if present). These methods are:
  - PUT
  - DELETE
  - POST

이 언어는 POST 요청을 캐시 할 수 없지만이 경우에는 사실이 아닙니다. 캐시는 이전에 저장된 데이터에 대해서만 무효화됩니다. RFC는 다음과 같이 명시 적으로 명시합니다. 예, POST요청 을 캐시 할 수 있습니다 .

9.5 POST

..

Responses to this method are not cacheable, unless the response
includes appropriate Cache-Control or Expires header fields. However,
the 303 (See Other) response can be used to direct the user agent to
retrieve a cacheable resource.

이 언어에도 불구하고, 설정은 Cache-Control후속 POST요청을 동일한 자원에 캐시해서는 안됩니다 . POST서버로 요청을 보내야합니다.

13.11 Write-Through Mandatory

..

All methods that might be expected to cause modifications to the
origin server's resources MUST be written through to the origin
server. This currently includes all methods except for GET and HEAD.
A cache MUST NOT reply to such a request from a client before having
transmitted the request to the inbound server, and having received a
corresponding response from the inbound server. This does not prevent
a proxy cache from sending a 100 (Continue) response before the
inbound server has sent its final reply.

어떻게 말이 되나요? 글쎄, 당신은 POST요청을 캐싱하지 않고 리소스를 캐싱하고 있습니다.

POST 응답 본문은 동일한 리소스에 대한 후속 GET 요청에 대해서만 캐시 될 수 있습니다. 본문이 나타내는 자원을 통신하도록 POST 응답에서 Location또는 Content-Location헤더를 설정하십시오 . 따라서 POST 요청을 캐시하는 기술적으로 유효한 유일한 방법은 동일한 GET에 대한 후속 GET입니다.

정답은 둘 다입니다.

  • "예, RFC를 사용하면 후속 GET에 대한 POST 요청을 동일한 리소스에 캐시 할 수 있습니다."
  • "아니요. POST는 dem 등원이 아니며 서버를 통해 작성되어야하므로 RFC는 후속 POST에 대한 POST 요청을 캐시 할 수 없습니다."

RFC를 통해 동일한 리소스에 대한 요청을 캐싱 할 수 있지만 실제로 브라우저와 CDN은이 동작을 구현하지 않으며 POST 요청을 캐시 할 수 없습니다.

출처 :

브라우저 동작 시연

다음 예제 JavaScript 응용 프로그램 (index.js)이 제공됩니다.

const express = require('express')
const app = express()

let count = 0

app
    .get('/asdf', (req, res) => {
        count++
        const msg = `count is ${count}`
        console.log(msg)
        res
            .set('Access-Control-Allow-Origin', '*')
            .set('Cache-Control', 'public, max-age=30')
            .send(msg)
    })
    .post('/asdf', (req, res) => {
        count++
        const msg = `count is ${count}`
        console.log(msg)
        res
            .set('Access-Control-Allow-Origin', '*')
            .set('Cache-Control', 'public, max-age=30')
            .set('Content-Location', 'http://localhost:3000/asdf')
            .set('Location', 'http://localhost:3000/asdf')
            .status(201)
            .send(msg)
    })
    .set('etag', false)
    .disable('x-powered-by')
    .listen(3000, () => {
        console.log('Example app listening on port 3000!')
    })

다음 예제 웹 페이지 (index.html)가 제공됩니다.

<!DOCTYPE html>
<html>

<head>
    <script>
        async function getRequest() {
            const response = await fetch('http://localhost:3000/asdf')
            const text = await response.text()
            alert(text)
        }
        async function postRequest(message) {
            const response = await fetch(
                'http://localhost:3000/asdf',
                {
                    method: 'post',
                    body: { message },
                }
            )
            const text = await response.text()
            alert(text)
        }
    </script>
</head>

<body>
    <button onclick="getRequest()">Trigger GET request</button>
    <br />
    <button onclick="postRequest('trigger1')">Trigger POST request (body 1)</button>
    <br />
    <button onclick="postRequest('trigger2')">Trigger POST request (body 2)</button>
</body>

</html>

NodeJS, Express를 설치하고 JavaScript 애플리케이션을 시작하십시오. 브라우저에서 웹 페이지를여십시오. 몇 가지 시나리오를 시도하여 브라우저 동작을 테스트하십시오.

  • "트리거 GET 요청"을 클릭하면 매번 동일한 "카운트"가 표시됩니다 (HTTP 캐싱 작동).
  • "Trigger POST request"를 클릭하면 매번 다른 카운트가 트리거됩니다 (POST에 대한 HTTP 캐싱이 작동하지 않음).
  • "Trigger GET request", "Trigger POST request"및 "Trigger GET request"를 클릭하면 POST 요청이 GET 요청의 캐시를 무효화 함을 표시합니다.
  • "Trigger POST request"를 클릭 한 다음 "Trigger GET request"를 클릭하면 RFC에서 허용하더라도 브라우저가 후속 GET 요청에 대한 POST 요청을 캐시하지 않습니다.

이는 Cache-ControlContent-Location응답 헤더를 설정할 수 있지만 브라우저를 HTTP POST 요청으로 캐시 할 수있는 방법이 없음을 보여줍니다 .

RFC를 따라야합니까?

브라우저 동작은 구성 할 수 없지만 브라우저가 아닌 경우 반드시 RFC 규칙에 구속되지 않아도됩니다.

응용 프로그램 코드를 작성하는 경우 POST 요청 (의사 코드)을 명시 적으로 캐싱하는 데 방해가되지 않습니다.

if (cache.get('hello')) {
  return cache.get('hello')
} else {
  response = post(url = 'http://somewebsite/hello', request_body = 'world')
  cache.put('hello', response.body)
  return response.body
}

CDN, 프록시 및 게이트웨이는 반드시 RFC를 따를 필요는 없습니다. 예를 들어 CDN으로 Fastly를 사용하는 경우 POST 요청캐시하는 사용자 지정 VCL 논리를 Fastly로 작성할 수 있습니다 .

POST 요청을 캐시해야합니까?

POST 요청을 캐시해야하는지 여부는 컨텍스트에 따라 다릅니다.

예를 들어, 기본 쿼리가 dem 등원 인 POST를 사용하여 Elasticsearch 또는 GraphQL을 쿼리 할 수 ​​있습니다. 이러한 경우 사용 사례에 따라 응답을 캐시하는 것이 합리적 일 수도 있고 그렇지 않을 수도 있습니다.

RESTful API에서 POST 요청은 일반적으로 리소스를 생성하므로 캐시해서는 안됩니다. 이것은 또한 POST가 dem 등원이 아니라는 RFC의 이해입니다.

GraphQL

GraphQL을 사용하고 CDN 및 브라우저에서 HTTP 캐싱이 필요한 경우 GET 메소드를 사용하여 쿼리를 보내는 것이 POST 대신 요구 사항을 충족하는지 고려하십시오 . 주의 사항에 따라 브라우저와 CDN마다 URI 길이 제한이 다를 수 있지만 외부 연결 프로덕션 GraphQL 앱의 모범 사례 인 작업 허용 목록 (쿼리 화이트리스트)은 URI를 단축 할 수 있습니다.


3

실제로 사이트의 데이터를 변경하지 않는 것이면 GET 요청이어야합니다. 양식 인 경우에도 가져 오기 요청으로 설정할 수 있습니다. 다른 사람들이 지적했듯이 POST의 결과를 캐시 할 수는 있지만 정의에 의한 POST가 데이터를 변경하기 때문에 의미 론적으로 의미가 없습니다.


POST 요청이 응답 페이지를 생성하는 데 사용되는 데이터를 변경하지 않을 수 있으며,이 경우 응답을 캐시하는 것이 좋습니다.
David Z

David Z : 확실히 POST가 데이터를 변경하면 응답에 성공 / 실패를 표시해야합니다. 정확히 요구되지는 않지만 POST가 데이터를 변경하고 응답이 정적 인 상황을 생각할 수 없습니다.
Morvael

6
매개 변수 데이터가 너무 길면 GET 요청이 모든 서버에서 작동하지 않으므로 POST는 특히 코드 작성자가 구성하지 않은 서버에서 소스를 실행해야하는 경우 필요합니다.
Gogowitsch

@ Gogowitsch 매우 사실, 414 오류 코드가 발생합니다.- stackoverflow.com
Siddhartha

-2

firefox 27.0 및 httpfox와 함께 2014 년 5 월 19 일에 한 줄을 보았습니다. 00 : 03 : 58.777 0.488 657 (393) POST (Cache) text / html https://users.jackiszhp.info/S4UP

분명히 post 메소드의 응답은 캐시되며 https에도 있습니다. 믿을 수 없는!


-3

POST는 상태 저장 Ajax에서 사용됩니다. POST에 대해 캐시 된 응답을 반환하면 통신 채널과 메시지 수신의 부작용이 사라집니다. 이것은 매우 나쁘다. 또한 추적하기가 정말 어려워요. 적극 권장합니다.

사소한 예는 부작용으로 현재 주에 급여 $ 10,000를 지불하는 메시지입니다. 당신은 "좋아, 통과했다!" 지난주에 캐시 된 페이지 더 복잡한 다른 실제 사례는 유사한 확대를 초래합니다.


3
별로 대답 - POST는 것을 때로는에 유효한 이유가 모든 종류의 사용 소원 캐시 응답은.
Alexei Levenkov
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.