programing

IIS에서 브라우저 캐싱 활용(구글 페이지 속도 문제)

javajsp 2023. 9. 11. 21:29

IIS에서 브라우저 캐싱 활용(구글 페이지 속도 문제)

브라우저 캐싱 활용에 대한 몇 가지 질문이 있지만 ASP에서 이를 수행하는 방법에 유용한 것을 찾지 못했습니다.NET 적용.구글의 페이지 속도는 이것이 성능의 가장 큰 문제라고 말합니다.지금까지 web.config에서 이 작업을 수행했습니다.

<system.webServer>
  <staticContent>
    <!--<clientCache cacheControlMode="UseExpires"
            httpExpires="Fri, 24 Jan 2014 03:14:07 GMT" /> -->
    <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.24:00:00" />
  </staticContent>
</system.webServer>

주석 코드가 작동합니다.만료 헤더를 미래의 특정 시간으로 설정할 수 있지만 설정할 수 없습니다.cacheControlMaxAge지금부터 정적 컨텐츠를 캐시할 날짜를 설정합니다.작동하지 않습니다.제 질문은 다음과 같습니다.

내가 어떻게 그럴 수 있을까?특정 폴더에 대해서만 캐싱을 설정하는 것이 가능하다는 것을 알고 있는데, 해결책도 되지 않습니다.응용 프로그램은 윈도우즈 Server 2012에서 호스팅되며, IIS8에서는 응용 프로그램 풀이 클래식으로 설정됩니다.

웹 구성에서 이 코드를 설정한 후 페이지 속도가 72(이전에는 71)가 되었습니다.50개의 파일이 캐시되지 않았습니다.(지금은 49) 왜 그런지 궁금했는데 한 파일이 실제로 캐시되어 있다는 것을 이제야 깨달았습니다(svg 파일).유감스럽게도 png와 jpg 파일은 그렇지 않았습니다.이것은 의 web.config 입니다.

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <configSections>
    <section name="exceptionManagement" type="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManagerSectionHandler,Microsoft.ApplicationBlocks.ExceptionManagement" />
    <section name="jsonSerialization"     type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions,   Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E34" requirePermission="false" allowDefinition="Everywhere" />
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah"    />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"    />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
    </sectionGroup>
  </configSections>

  <exceptionManagement mode="off">
    <publisher mode="off" assembly="Exception"  type="blabla.ExceptionHandler.ExceptionDBPublisher"  connString="server=188......;database=blabla;uid=blabla;pwd=blabla; " />
  </exceptionManagement>
  <location path="." inheritInChildApplications="false">
    <system.web>
      <httpHandlers>
        <add verb="GET,HEAD" path="ScriptResource.axd"  type="System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions, Version=1.0.61025.0,  Culture=neutral, PublicKeyToken=31bf3856ad364e34" validate="false" />
        <add verb="GET" path="Image.ashx" type="blabla.WebComponents.ImageHandler, blabla/>"
        <add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
        <add verb="*" path="*.jpg" type="System.Web.StaticFileHandler" />
        <add verb="GET" path="*.js" type="System.Web.StaticFileHandler" />
        <add verb="*" path="*.gif" type="System.Web.StaticFileHandler" />
        <add verb="GET" path="*.css" type="System.Web.StaticFileHandler" />
      </httpHandlers>
      <compilation defaultLanguage="c#" targetFramework="4.5.1" />
      <trace enabled="false" requestLimit="100" pageOutput="true" traceMode="SortByTime" localOnly="true"/>
      <authentication mode="Forms">
        <forms loginUrl="~/user/login.aspx">
          <credentials passwordFormat="Clear">
            <user name="blabla" password="blabla" />
          </credentials>
        </forms>
      </authentication>
      <authorization>
        <allow users="*" />
      </authorization>
      <sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" />
      <globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="en-GB" uiCulture="en-GB" />
      <xhtmlConformance mode="Transitional" />
      <pages controlRenderingCompatibilityVersion="4.5" clientIDMode="AutoID">
        <namespaces>

        </namespaces>
        <controls>
          <add assembly="Microsoft.AspNet.Web.Optimization.WebForms" namespace="Microsoft.AspNet.Web.Optimization.WebForms" tagPrefix="webopt" />
        </controls>
      </pages>
      <webServices>
        <protocols>
          <add name="HttpGet" />
          <add name="HttpPost" />
        </protocols>
      </webServices>
    </system.web>
  </location>
  <appSettings>

  </appSettings>
  <connectionStrings>

  </connectionStrings>
  <system.web.extensions>
    <scripting>
      <webServices>
        <jsonSerialization maxJsonLength="200000" />
      </webServices>
    </scripting>
  </system.web.extensions>
  <startup>
    <supportedRuntime version="v2.0.50727" />
    <supportedRuntime version="v1.1.4122" />
    <supportedRuntime version="v1.0.3705" />
  </startup>
  <system.webServer>


    <rewrite>
      <providers>
        <provider name="ReplacingProvider" type="ReplacingProvider, ReplacingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5ab632b1f332b247">
          <settings>
            <add key="OldChar" value="_" />
            <add key="NewChar" value="-" />
          </settings>
        </provider>
        <provider name="FileMap" type="DbProvider, Microsoft.Web.Iis.Rewrite.Providers, Version=7.1.761.0, Culture=neutral, PublicKeyToken=0525b0627da60a5e">
          <settings>
            <add key="ConnectionString" value="server=;database=blabla;uid=blabla;pwd=blabla;App=blabla"/>
            <add key="StoredProcedure" value="Search.GetRewriteUrl"/>
            <add key="CacheMinutesInterval" value="0"/>
          </settings>
        </provider>
      </providers>
      <rewriteMaps configSource="rewritemaps.config" />
      <rules configSource="rewriterules.config" />
    </rewrite>
    <modules>
      <remove name="ScriptModule" />
      <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3456AD264E35" />
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    <handlers>
      <add name="Web-JPG" path="*.jpg" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
      <add name="Web-CSS" path="*.css" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
      <add name="Web-GIF" path="*.gif" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
      <add name="Web-JS" path="*.js" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
    </handlers>
    <validation validateIntegratedModeConfiguration="false" />
    <httpErrors errorMode="DetailedLocalOnly" existingResponse="Auto">
      <remove statusCode="404" subStatusCode="-1"/>
      <remove statusCode="500" subStatusCode="-1"/>
      <error statusCode="404" path="error404.htm" responseMode="File"/>
      <error statusCode="500" path="error.htm" responseMode="File"/>
    </httpErrors>
  </system.webServer>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="soapBinding_AdriagateService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true" messageEncoding="Text">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <security mode="None" />
        </binding>
      </basicHttpBinding>
      <netTcpBinding>
        <binding name="NetTcpBinding_ITravellerService" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="blabla" bindingConfiguration="soapBinding_blabla" contract="" Address="blabla" name="blabla" />
        <endpoint address="blabla" binding="basicHttpBinding" bindingConfiguration="soapBinding_IImagesService"
          contract="ImagesService.IImagesService" name="soapBinding_IImagesService"/>
        <identity>
          <servicePrincipalName value="blabla"/>
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.5.0.0" newVersion="4.5.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.web>
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
  </system.web>
  <elmah>
    <security allowRemoteAccess="false" />
  </elmah>
  <location path="elmah.axd" inheritInChildApplications="false">
    <system.web>
      <httpHandlers>
        <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
      </httpHandlers>

    </system.web>
    <system.webServer>
      <handlers>
        <add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
      </handlers>
    </system.webServer>
  </location>
</configuration>

편집: 정확한 만료 날짜를 설정하면 캐싱이 작동하지만 jpg,gif....에 대해서는 작동하지 않습니다. png에 대해서만.

EDIT2: 설정한 경우cacheControlCustom="public"여기와 같이:

<clientCache cacheControlCustom="public" 
cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" /> 

캐싱은 작동하지만 여전히 jpegs와 gif에는 작동하지 않습니다. svgs와 pngs에만 작동합니다.

대부분의 브라우저 캐싱 문제는 응답 헤더를 보고 해결할 수 있습니다(Google chrome developer 도구에서 수행 가능).

enter image description here

는.clientCache당신의web.config에서 볼 수 .max-age86400초 단위로 1일입니다.

다음은 이 설정에 대한 web.config 스니펫입니다.

<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />

에는 요, 이 .max-ageCache-Control머리말따라서 브라우저는 콘텐츠를 캐싱해야 합니다.이것은 대부분 사실이지만 일부 브라우저에서는 다른 플래그를 설정해야 합니다.구체적으로.public캐시 제어 헤더에 대해 설정된 플래그입니다.이를 사용하여 쉽게 추가할 수 있습니다.cacheControlCustom의에 합니다.web.config예가 . 여기 예가 있습니다.

<clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />

이제 페이지를 재시도하고 헤더를 검사할 때입니다.

enter image description here

에서 볼 수 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δpublic, max-age=86400 우리 데 것을 . 그래서 우리 브라우저는 리소스를 캐싱하는 데 필요한 모든 것을 가지고 있습니다.이제 구글 크롬의 헤더와 네트워크 탭을 조사하는 것이 도움이 될 것입니다.

파일에 대한 첫번째 요청입니다.파일이 캐시되지 않았습니다...enter image description here

이제 이 페이지로 다시 이동합니다(참고: 페이지를 새로 고치지 마십시오. 잠시 후에 이에 대해 설명하겠습니다).지금 캐시에서 응답이 반환됩니다(원으로 표시됨).

enter image description here

이제 브라우저 새로 고침 기능을 사용하거나 둘 중 하나를 사용하여 페이지를 새로 고치면 어떻게 됩니까?잠깐만..어디서(from cache)가세요.enter image description here

구글 크롬에서는 새로 고침 버튼을 사용하면 캐시 헤더에 관계없이 정적 리소스가 다시 다운로드됩니다(여기에 설명을 삽입하십시오).즉, 리소스가 다시 검색되고 최대 헤더가 전송되었음을 의미합니다.

이제 위의 모든 설명을 마치고 캐시 헤더를 어떻게 모니터링하고 있는지 테스트해 보십시오.

갱신하다

핸들러 handler)가 말씀하셨습니다. (IHttpHandler)의 이름을 붙였습니다Image.ashx내용 유형은 다음과 같습니다.image/jpg은 이입니다. 기본 동작은 이 핸들러를 캐시하는 것입니다. "IIS"가 됩니다..ashx코드 자체에 캐시 헤더를 명시적으로 설정하지 않고는 캐싱 대상이 되지 않으며, 동적 스크립트로 사용됩니다.

일반적으로 여기서 주의를 기울여야 합니다.IHttpHandlers일반적으로 동적 컨텐츠를 제공하기 때문에 캐시되지 않아야 합니다.내용이 변경되지 않을 경우에는 캐시 헤더를 코드에 직접 설정할 수 있습니다.시정는과다의다sne에서 캐시 헤더를 설정하는 예입니다.IHttpHandlersResponse맥락.

context.Response.ContentType = "image/jpg";

context.Response.Cache.SetMaxAge(TimeSpan.FromDays(1));
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetSlidingExpiration(true);

context.Response.TransmitFile(context.Server.MapPath("~/out.jpg"));

를 는 을 하고 에 몇 가지 을 설정하고 .Cache 을 얻기 했습니다.원하는 응답을 얻기 위해 속성을 설정했습니다.

  • context.Response.Cache.SetMaxAge(TimeSpan.FromDays(1));력에을록다e을 설정하도록 지시합니다.max-age=Cache-Control머리말이 될1미래의 하루(86400초).
  • context.Response.Cache.SetCacheability(HttpCacheability.Public);력에을록다e을 설정하도록 지시합니다.Cache-Controlo로 머리글을 .public합니다. 이는 브라우저에 개체를 캐시하도록 지시하기 때문에 매우 중요합니다.
  • context.Response.Cache.SetSlidingExpiration(true);력에을고지다다etegose에e을력tsmax-age=Cache-Control머리말을 제대로 합니다.슬라이딩 만료를 설정하지 않으면 IIS 출력 캐싱이 maxage 헤더를 무시합니다.이것을 종합해보면 이런 결과가 나옵니다.

output cache from ashx file

위에서 말한 것처럼 당신은 캐시를 원하지 않을 수도 있습니다..ashx일반적으로 동적 컨텐츠를 제공하는 파일입니다. 해당 이 특정 나당가정간에지을다수을할여을의우적다r수할r을나esroteescnu당nftadyne적to.ashx파일.파일.

이제 위에 나열된 프로세스와 함께 사용자 정의 문자열로 전달되는 내용을 브라우저가 확인할 수 있도록 캐시 헤더의 ETag(wiki 참조) 구성 요소도 설정할 수 있습니다.위키에는 다음과 같이 명시되어 있습니다.

웹 의 특정 입니다. 그 되면, ETag의 URL이 변경됩니다. 만약 그 URL의 리소스 내용이 변경된다면, 새로운 것과 다른 것입니다.ETag가 할당됩니다.

이는 브라우저가 응답에서 제공되는 내용을 식별하기 위한 일종의 고유한 식별 정보입니다. 시 이를전시가를해다음 aar다를해dya가이를enrresl면gIf-None-Match머리글에 다음과 같이 붙입니다.ETag마지막 회답에서우리는 우리의 핸들러를 수정하여 그들을 감지할 수 있습니다.If-None-Match와한과다가r과t한rdo와가와 비교합니다.Etag. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .ETags그러나 경험칙은 하나의 개체만을 정의할 가능성이 높은 식별자를 제공하는 것입니다.이 경우 다음과 같이 연결된 두 문자열을 사용하는 것이 경우

System.IO.FileInfo file = new System.IO.FileInfo(context.Server.MapPath("~/saveNew.png"));
string eTag = file.Name.GetHashCode().ToString() + file.LastWriteTimeUtc.Ticks.GetHashCode().ToString();

위의 토막글에서는 파일 시스템에서 파일을 로드하고 있습니다(어디서나 얻을 수 있습니다).저는 그럼 사용하고 있습니다.GetHashCode()메서드(모든 개체에 대해)를 지정하여 개체의 정수 해시 코드를 가져옵니다.예제에서 파일 이름의 해시, 마지막 쓰기 날짜를 연결합니다.마지막 쓰기 날짜의 이유는 파일이 변경된 경우 해시 코드도 변경되어 지문이 달라지기 때문입니다.

그러면 다음과 같은 해시 코드가 생성됩니다.306894467-210133036.

그럼 핸들러에서 이걸 어떻게 사용하죠?아래는 핸들러의 새롭게 수정된 버전입니다.

System.IO.FileInfo file = new System.IO.FileInfo(context.Server.MapPath("~/out.png"));
string eTag = file.Name.GetHashCode().ToString() + file.LastWriteTimeUtc.Ticks.GetHashCode().ToString();
var browserETag = context.Request.Headers["If-None-Match"];

context.Response.ClearHeaders();
if(browserETag == eTag)
{
    context.Response.Status = "304 Not Modified";
    context.Response.End();
    return;
}
context.Response.ContentType = "image/jpg";
context.Response.Cache.SetMaxAge(TimeSpan.FromDays(1));
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetSlidingExpiration(true);
context.Response.Cache.SetETag(eTag);
context.Response.TransmitFile(file.FullName);

보시다시피 핸들러를 꽤 많이 바꿨지만 우리가 생성하는 것을 알게 될 것입니다.Etag시,신인rn신,If-None-Match반환하여 내용이 변경되지 않았음을 브라우저에 알립니다.304 Not Modified.

다음은 우리가 추가하는 것을 제외하고는 같은 핸들러였습니다.ETag헤더 호출:

context.Response.Cache.SetETag(eTag);

이것을 브라우저에서 실행하면 얻을 수 있습니다.

Cache-Control with ETag

(파일 이름을 변경한 것과 같이) 이미지를 보면 캐시 시스템의 모든 구성 요소가 자리 잡았음을 알 수 있을 것입니다.ETag 헤더고서청를다고며다e고g를s로청고서며estgdrs .If-None-Match변경된 캐시 파일에 따라 저희 핸들러가 대응할 수 있도록 합니다.

이거 써요.이건 저한테 효과가 있어요.

<staticContent>
<clientCache cacheControlMode="UseExpires" httpExpires="Tue,19 Jan 2038 03:14:07 GMT"/>
</staticContent>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="10.00:00:00" />
    </staticContent>
  </system.webServer>
</configuration>

위 내용을 이용하면 브라우저에서 10일간 정적 내용 파일이 캐시됩니다.한한보e에 대한 상세 정보<clientCache>요소는 여기서 찾을 수 있습니다.

사용할 수도 있습니다.<location>특정 파일의 캐시 설정을 정의하는 요소:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <location path="path/to/file">
    <system.webServer>
      <staticContent>
        <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="10.00:00:00" />
      </staticContent>
    </system.webServer>
  </location>
</configuration>

언급URL : https://stackoverflow.com/questions/21074198/leverage-browser-caching-in-iis-google-pagespeed-issue