다음을 통해 공유


IHttpCachePolicy::GetVaryByHeaders 메서드

캐시 정책에 대한 사용자 지정 헤더 값을 반환합니다.

구문

virtual PCSTR GetVaryByHeaders(  
   VOID  
) const = 0;  

매개 변수

이 메서드는 매개 변수를 사용하지 않습니다.

반환 값

사용자 지정 헤더 값의 쉼표로 구분된 목록을 포함하는 null로 종료 PCSTR 된 입니다.

설명

요청 또는 응답 이벤트에 등록하는 CHttpModule 파생 클래스는 해당 virtual 메서드의 매개 변수로 IHttpContext 포인터를 받습니다. IHttpContext::GetResponse 메서드를 호출한 다음, IHttpResponse::GetCachePolicy 메서드를 호출하고, 마지막으로 GetVaryByHeaders 메서드를 호출하여 사용자 지정 헤더를 검색합니다.

GetVaryByHeaders 동작은 구현에 따라 달라집니다. 다음 정보를 지침으로 사용해야 하지만 모든 시나리오에서 올바르지 않을 수 있습니다.

  • IHttpCachePolicy 인터페이스의 현재 기본 구현자는 변수 헤더 데이터가 포함된 버퍼를 선언합니다private. 구현자를 생성하는 동안 이 버퍼는 비어 있는 것으로 초기화됩니다. 제공된 매개 변수가 NULL이면 AppendVaryByHeader 메서드는 즉시 S_OK 반환합니다. 그렇지 않으면 버퍼가 확장되어 null 종료 문자를 비롯한 매개 변수의 복사본과 버퍼가 현재 비어 있지 않은 경우 1을 포함합니다. 버퍼가 비어 있지 않으면 "" 문자가 버퍼에 추가됩니다. 마지막으로 null 종료 문자를 포함하여 매개 변수의 내용이 버퍼에 추가됩니다.

  • GetVaryByHeaders 는 에 대한 연속 호출을 통해 설정된 사용자 지정 헤더의 쉼표로 AppendVaryByHeader구분된 목록을 반환합니다.

구현자에 대한 참고 사항

IHttpCachePolicy구현자는 이 데이터를 사용하여 메모리 관리를 담당합니다. 따라서 IHttpCachePolicy 동적 메모리 할당을 사용하는 구현자는 더 이상 필요하지 않은 경우 포인터를 PCSTR 해제하거나 를 호출 delete 해야 합니다.

호출자 참고 사항

IHttpCachePolicy구현자는 이 데이터를 사용하여 메모리 관리를 담당합니다. 따라서 IHttpCachePolicy 클라이언트는 이 데이터가 더 이상 필요하지 않을 때 반환 PCSTR 된 포인터를 해제하거나 호출 delete 하지 않아야 합니다. 또한 액세스 위반이 throw되거나 데이터가 잘못되기 때문에 클라이언트는 이 데이터를 가 아닌 const 포인터로 캐스팅하거나 이 PCSTR에서 참조하는 메모리의 상태를 변경해서는 안 됩니다.

예제

다음 코드 예제에서는 RQ_BEGIN_REQUEST 및 RQ_SEND_RESPONSE 이벤트를 수신 대기하는 전역 모듈을 만드는 방법을 보여 줍니다. 그런 다음, 모듈은 포인터를 IHttpCachePolicy 검색하고 변수 헤더 정보를 응답 스트림에 씁니다.

#pragma warning( disable : 4290 )
#pragma warning( disable : 4530 )

#define _WINSOCKAPI_
#include <windows.h>
#include <sal.h>
#include <tchar.h>
#include <httptrace.h>
#include <httpserv.h>
#include <httpcach.h>

#include <string>
using namespace std;

// The CConvert class mirrors the Convert class that is 
// defined in the .NET Framework. It converts primitives 
// and other data types to wstring types.
class CConvert
{
public:
    // The ToString method converts a PCSTR to a wstring.
    // pcstr: the PCSTR to convert to a wstring.
    // return: the PCSTR as a wstring.
    static wstring ToString(PCSTR pcstr)
    {
        // Return the empty string 
        // if the PCSTR is NULL.
        if (NULL == pcstr)
        {
            return L"NULL";
        }

        // Get the length of the string to copy.
        size_t length = strlen(pcstr);
        // Create a new double-byte character 
        // array of length plus 1.
        wchar_t* newText = new wchar_t[length+1];

        // Copy the source into the sink string.
        for (size_t i = 0; i < length; ++i)
        {
            newText[i] = pcstr[i];
        }

        // Terminate the string with the NULL character.
        newText[length] = '\0';
        // Get a wstring from the new double-byte string.
        wstring wText = newText;
        // Call delete on the newText pointer 
        // and set this pointer to NULL.
        delete[] newText;
        newText = NULL;

        // Return the wstring copy.
        return wText;
    }

    // The ToByteString converts a double-byte 
    // character string to a single-byte string.
    // str: the double-byte string to convert.
    // return: a single-byte string copied from str.
    static string ToByteString(const wstring& str)
    {
        // Get the length of the 
        // double-byte string.
        size_t length = str.length();

        // Create a temporary char pointer.
        char* byteChar = new char[length+1];
        byteChar[0] = '\0';
        // Copy the double-byte character string
        // into the single-byte string.        
        size_t charsReturned = 0;
        wcstombs_s(&charsReturned, byteChar, 
                   length+1, str.c_str(), length+1);
        // Create a string to return.
        string retString = byteChar;
        // Delete the temporary string and
        // set that string to NULL.
        delete[] byteChar;
        byteChar = NULL;

        // Return the single-byte string.
        return retString;
    }
};

// The CResponseWriter class writes 
// text to the response stream.
class CResponseWriter
{
public:
    // Creates the CResponseWriter class.
    // response: the IHttpResponse 
    // pointer to write to.
    // throws: a _com_error exception if
    // the IHttpResponse pointer is NULL.
    CResponseWriter(IHttpResponse* response)
        throw (_com_error)
    {
        // If the response is NULL,
        // throw an exception.
        if (NULL == response)
        {
            ThrowOnFail(E_INVALIDARG);            
        }

        // Set the internal response.
        m_response = response;
    }

    // The destructor for the CResponseWriter
    // class. The CResponseWriter method 
    // sets the IHttpResponse pointer to NULL.
    virtual ~CResponseWriter()
    {
        m_response = NULL;
    }
    
    // The Write method writes the 
    // PCSTR to the response stream.
    // pszValue: the PCSTR to write.
    // throws: a _com_error if the 
    // Write method fails.
    void Write
    (
        PCSTR pszValue        
    ) throw (_com_error)
    {
        // The string must not be 
        // NULL, and its length must 
        // be greater than 0.
        if ((NULL == pszValue) || 
            (strlen(pszValue) < 1))            
        {
            // Throw an invalid argument
            // exception.
            ThrowOnFail(E_INVALIDARG);                        
        }        

        // Create a data chunk structure.
        HTTP_DATA_CHUNK dataChunk;
        // Set the chunk to a chunk in memory.
        dataChunk.DataChunkType = 
            HttpDataChunkFromMemory;

        // Set the chunk to 
        // the pszValue parameter.
        dataChunk.FromMemory.pBuffer = 
            (PVOID)pszValue;
        // Set the chunk size 
        // to the pszValue length.
        dataChunk.FromMemory.BufferLength = 
            (USHORT)strlen(pszValue);
                
        // Declare and initialize OUT 
        // parameters for the WriteEntityChunks 
        // method.
        DWORD pcbSent = 0;
        BOOL pfCompletionExpected = FALSE;

        // Write the entity chunks to
        // the response stream.
        HRESULT hr =
            m_response->WriteEntityChunks
                (&dataChunk,
                 1,
                 FALSE,
                 FALSE,
                 &pcbSent,
                 &pfCompletionExpected);

        // Throw an exception if the call
        // to WriteEntityChunks is not a 
        // success.
        ThrowOnFail(hr);        
    }
    
    // The WriteLine method writes a string
    // and newline characters to the response steam.
    // pszValue: the PCSTR string to write.
    // throws: a _com_error if the PCSTR 
    // or the newline characters are not 
    // written to the response stream.
    void WriteLine
    (
        PCSTR pszValue        
    ) throw (_com_error)
    {
        // Try to write the pszValue parameter.
        Write(pszValue);        
        
        // Try to write the newline characters.
        Write("\r\n");
    }
    
    // Convenience method that writes a name 
    // and value pair to the response stream.
    // name: the name of the parameter.
    // value: the value of the parameter.
    // throws: a _com_error exception if
    // the response stream is not written.
    void WriteLine
    (
        const wstring& name,
        const wstring& value
    ) throw (_com_error)
    {
        // Convert the UNICODE strings 
        // to mutlibyte strings.
        string nameMulti = 
            CConvert::ToByteString(name);
        string valueMulti = 
            CConvert::ToByteString(value);

        // Create the string to write.
        string writeString =
            nameMulti + 
            string(":  ") + 
            valueMulti;

        // Write the line to
        // the response stream.
        WriteLine(writeString.c_str());        
    }

    // Tests an HRESULT for success.
    // hr: the HRESULT value to inspect.
    // throws: a _com_error if the HRESULT
    // parameter is not S_OK.
    static void ThrowOnFail(HRESULT hr)
    {
        if (FAILED(hr))
        {
            _com_error ce(hr);
            throw ce;
        }
    }
private:
    // Specify the IHttpResponse
    // pointer to write to.
    IHttpResponse* m_response;
};

// The CCachePolicyModule is a CHttpModule 
// class that handles response processing
// by updating the IHttpCachePolicy pointer
// and writing that IHttpCachePolicy data
// to the response stream.
class CCachePolicyModule : public CHttpModule
{
public:

    // The CHttpResponseModule method is 
    // the public virtual destructor for 
    // the CHttpResponseModule class.
    virtual ~CCachePolicyModule()
    {

    }

    // The OnSendResponse method is the method 
    // supporting the RQ_SEND_RESPONSE event type.
    // pHttpContext: the current IHttpContext pointer.
    // pProvider: the current IHttpEventProvider pointer.
    // return: RQ_NOTIFICATION_FINISH_REQUEST if the
    // IHttpCachePolicy data is written. Otherwise, 
    // RQ_NOTIFICATION_CONTINUE.
    virtual 
    REQUEST_NOTIFICATION_STATUS
    OnSendResponse
    (
        IN IHttpContext* pHttpContext,
        IN ISendResponseProvider* pProvider
    )
    {
        // Return if the IHttpContext
        // pointer is NULL.
        if (NULL == pHttpContext)
        {
            return RQ_NOTIFICATION_CONTINUE;
        }

        // Get the IHttpResponse pointer 
        // from the IHttpContext pointer.
        IHttpResponse* response = 
            pHttpContext->GetResponse();

        // Return if the IHttpResponse 
        // pointer is NULL.
        if (NULL == response)
        {
            return RQ_NOTIFICATION_CONTINUE;
        }

        // Get the IHttpCachePolicy pointer
        // from the IHttpResponse pointer.
        IHttpCachePolicy* policy =
            response->GetCachePolicy();
    
        // Return if the IHttpCachePolicy
        // pointer is NULL.
        if (NULL == policy)
        {
            return RQ_NOTIFICATION_CONTINUE;
        }

        // Wrap calls in one try-catch statement
        // because a CResponseWriter might throw
        // a _com_error exception.
        try
        {
            // Create a CResponseWriter using
            // the IHttpResponse pointer.
            CResponseWriter writer(response);

            // Clear the existing response stream.
            response->Clear();

            // Set the response header to plain text.
            HRESULT hr = 
                response->SetHeader(HttpHeaderContentType, 
                                    "text/plain", 
                                    (USHORT)strlen("text/plain"), 
                                     TRUE);

            // Throw an excepion if the
            // SetHeader method failed.
            CResponseWriter::ThrowOnFail(hr);

            // Write the IHttpCachePolicy pointer 
            // data to the response stream.
            Write(policy, writer);
        }
        catch(_com_error& ce)
        {
            // Set the error status 
            // using the COM exception.
            response->SetStatus(500,
                                "OnSendResponse",
                                0, ce.Error());
            // Continue processing.
            return RQ_NOTIFICATION_CONTINUE;
        }
    
        // Finish the request because
        // the response is written.
        return RQ_NOTIFICATION_FINISH_REQUEST;
    }
protected:

    // The Write method writes IHttpCachePolicy
    // pointer data to the response stream.
    // httpCachePolicy: the IHttpCachePolicy
    // pointer to write to the stream.
    // writer: the CResponseWriter writer
    // for writing to the response stream.
    // throws: a _com_error exception.
    static void Write
    (
        IHttpCachePolicy* httpCachePolicy,
        CResponseWriter& writer
    ) throw (_com_error)
    {
        // If the IHttpCachePolicy 
        // pointer is NULL, return.
        if (NULL == httpCachePolicy)
        {
            return;
        }

        // Get the vary-by-headers from
        // the IHttpCachePolicy pointer.
        PCSTR varyByHeadersPCSTR = 
            httpCachePolicy->GetVaryByHeaders();

        // Convert the vary-by-headers 
        // to a wstring.
        wstring varyByHeaders = 
            CConvert::ToString(varyByHeadersPCSTR);

        // Write the Vary-by-headers 
        // to the response stream.
        writer.WriteLine(L"Vary-by-Headers", varyByHeaders);        
    }
};

// The CCachePolicyFactory class implements the 
// IHttpModuleFactory interface and creates a new 
// CCachePolicyModule pointer and registers that 
// pointer for request and response events.
class CCachePolicyFactory : public IHttpModuleFactory
{
public:
    // The RegisterCHttpModule method creates a new 
    // CCachePolicyFactory pointer and sets this new 
    // CCachePolicyFactory pointer as the IHttpModuleFactory 
    // pointer on the IHttpModuleRegistrationInfo pointer.
    // dwServerVersion: the current server version.
    // pModuleInfo: the current 
    // IHttpModuleRegistrationInfo pointer.
    // pGlobalInfo: the current IHttpServer pointer.
    // return: the value returned from the the call 
    // to the SetRequestNotifications on the 
    // IHttpModuleRegistrationInfo pointer.
    static HRESULT RegisterCHttpModule
    (
        DWORD dwServerVersion,
        IHttpModuleRegistrationInfo* pModuleInfo,
        IHttpServer* pGlobalInfo
    )
    {
        // Create a new CCachePolicyFactory pointer.
        CCachePolicyFactory* policyFactory = 
            new CCachePolicyFactory;

        // Test for NULL on the new 
        // CCachePolicyFactory pointer.
        if (NULL == policyFactory)
        {
            // Return an out-of-memory error 
            // code if moduleFactory is NULL.
            return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
        }

        // Set the request notifications for RQ_SEND_RESPONSE 
        // messages on the new CCachePolicyFactory pointer.
        return pModuleInfo->SetRequestNotifications
                (policyFactory,
                 RQ_SEND_RESPONSE,
                 0); 
    }
    
    // The GetHttpModule method creates a new 
    // CCachePolicyModule pointer and sets the 
    // new CCachePolicyModule on the ppModule parameter.
    // ppModule: the new CHttpResponseModule pointer to return.
    // pAllocator: currently unused.
    // return: ERROR_NOT_ENOUGH_MEMORY if the 
    // heap is exhausted; otherwise, S_OK.
    virtual
    HRESULT
    GetHttpModule
    (
        OUT CHttpModule** ppModule, 
        IN IModuleAllocator* pAllocator
    )
    {
        // Call the UNREFERENCED_PARAMETER macro 
        // with the IModuleAllocator pointer, because 
        // this parameter is currently unused.
        UNREFERENCED_PARAMETER(pAllocator);

        // Set the dereferenced ppModule 
        // to a new CHttpResponseModule pointer.
        (*ppModule) = new CCachePolicyModule;

        // If the new CHttpResponseModule is 
        // NULL, return an error indicating 
        // that heap memory is exhausted.
        if (NULL == (*ppModule))
        {
            return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
        }

        // Return S_OK.
        return S_OK;
    }
    
    // The Terminate method 
    // calls delete on this.
    virtual 
    void
    Terminate()
    {
        delete this;
    }    
protected:
    // The CCachePolicyFactory method is 
    // the protected constructor for the 
    // CCachePolicyFactory class.
    CCachePolicyFactory()
    {
        
    }

    // The CCachePolicyFactory method is 
    // the protected virtual destructor for 
    // the CCachePolicyFactory class.
    virtual ~CCachePolicyFactory()
    {
        
    }
private:
};

// The RegisterModule method is the 
// main entry point for the DLL.
// dwServerVersion: the current server version.
// pModuleInfo: the current 
// IHttpModuleRegistrationInfo pointer.
// pGlobalInfo: the current IHttpServer pointer.
// return: the value returned by calling the 
// CCachPolicyFactory::RegisterCHttpModule method.
HRESULT
__stdcall
RegisterModule(
    DWORD dwServerVersion,
    IHttpModuleRegistrationInfo* pModuleInfo,
    IHttpServer* pGlobalInfo
)
{
    return CCachePolicyFactory::RegisterCHttpModule
        (dwServerVersion, 
         pModuleInfo, 
         pGlobalInfo);    
}

네이티브 DLL 모듈을 만들고 배포하는 방법에 대한 자세한 내용은 연습: 네이티브 코드를 사용하여 Request-Level HTTP 모듈 만들기를 참조하세요.

위의 코드는 응답 스트림에 다음과 유사한 데이터를 씁니다.

Vary-by-Headers:   

필요에 따라 각 함수에 대한 호출 규칙을 명시적으로 선언하는 대신 __stdcall (/Gz) 호출 규칙을 사용하여 코드를 컴파일할 수 있습니다.

요구 사항

형식 Description
클라이언트 - Windows Vista의 IIS 7.0
- Windows 7의 IIS 7.5
- Windows 8의 IIS 8.0
- WINDOWS 10 IIS 10.0
서버 - Windows Server 2008의 IIS 7.0
- Windows Server 2008 R2의 IIS 7.5
- Windows Server 2012의 IIS 8.0
- Windows Server 2012 R2의 IIS 8.5
- WINDOWS SERVER 2016 IIS 10.0
제품 - IIS 7.0, IIS 7.5, IIS 8.0, IIS 8.5, IIS 10.0
- IIS Express 7.5, IIS Express 8.0, IIS Express 10.0
헤더 Httpserv.h

참고 항목

IHttpCachePolicy 인터페이스