【问题标题】:Can .NET intercept and change css files?.NET 可以拦截和更改 css 文件吗?
【发布时间】:2011-09-06 05:23:06
【问题描述】:

更新 1:

我现在已经设置了 IIS6,因此 .NET 可以处理对 .css 文件的调用。我现在需要做什么才能让它根据引用 url 更改 css 文件?因此,如果引用 url 是 http://intranet/,它应该继续调用旧样式表。如果引用 url 是http://intranetv2/,它应该调用新的样式表。


原始问题:

背景:

我有 2 个搜索引擎。一个是旧的,另一个是全新的(发展阶段)。搜索引擎 1 在 domain1.com 上,搜索引擎 2 在 domain2.com 上。两个域都在同一台服务器上。两者都根据用户在搜索引擎中输入的内容来搜索 domain1.com 上的网页。两个搜索引擎之间的区别在于,新的搜索引擎速度更快,结果更准确,并且用户界面有了很大改进。两个搜索引擎都将保持运行状态,以便用户可以在自己的时间习惯新的搜索引擎,而不是仅仅将它们扔到深处并完全删除旧的搜索引擎。

无论如何,背景已经足够了,基本上,因为可搜索页面使用旧搜索引擎驻留在旧域名上,而新搜索引擎在新域名上,...

问题:

...我可以使用 HttpModule,或 .NET 的其他部分,或来自 IIS6 的东西来捕获新搜索引擎生成的页面链接,并在旧的可搜索页面上动态更改附加到旧可搜索页面的 css 文件域?

原因:

实际上使它看起来像一个全新的网站,如果旧域上的搜索引擎用于访问旧域上的页面,则使用旧样式表,但如果新域上的搜索引擎用于访问旧域名上的可搜索文件,应使用新样式表使旧页面看起来新。由于有很多可搜索的页面,在 10,000 左右,在向页面添加样式表之前编辑每个页面以添加 if 语句来检查引荐域名是不现实的选择。

环境:

旧的搜索引擎,以及旧域上的可搜索页面使用 .net 1.something,但新域名上的新搜索引擎使用 .net 3.5,而我使用 vb.net 作为 asp .net 页面。服务器是 IIS6 服务器。

【问题讨论】:

  • 您可以简单地将其添加为新主题,并根据主 PreInit 事件中的 HttpRequest.Url 动态切换主题,或者在下面我的答案中检查处理程序。

标签: .net asp.net .net-3.5 httpmodule .net-1.0


【解决方案1】:
  1. 在 IIS 中,设置 HttpHandler 以接收您想要的所有文件类型(说明您已经这样做了)
  2. 用户Server.MapPath()HttpRequest.Url.AbsolutePath获取物理路径
  3. 根据域修改路径
  4. 将文件写入响应流。

这是一个处理程序(简化),我经常使用它来为不同域提供备用文件:

using System;
using System.IO;
using System.Web;
public class MultiDomainFileHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string filePath = GetDomainSpecificFilePath(context.Request.Url.Host,
            context.Server.MapPath(context.Request.Url.AbsolutePath));

        if (File.Exists(filePath))
        {
            switch (Path.GetExtension(filePath).ToLower())
            {
                case ".css": context.Response.ContentType = "text/css"; break;
                case ".jpg":
                case ".jpeg": context.Response.ContentType = "image/jpeg"; break;
                //other types you want to handle
                default: context.Request.ContentType = "application/octet-stream"; break;
            }
            context.Response.WriteFile(filePath); //Write the file to response
        }
        else context.Response.StatusCode = 404;
    }

    private string GetDomainSpecificFilePath(string domain, string originalPath)
    {
        string prefix = "";
        switch (domain.ToLower())
        {
            case "intranetv2": prefix = FILE_PREFIX_INTRANETV2; break;
            case "www.example.com": prefix = FILE_PREFIX_EXAMPLE_DOT_COM; break;
            //other domains you want to handle
        }
        string dir = Path.GetDirectoryName(originalPath);
        string fileName = prefix + Path.GetFileName(originalPath);
        return Path.Combine(dir, fileName);
    }

    const string FILE_PREFIX_INTRANETV2 = "v2.", FILE_PREFIX_EXAMPLE_DOT_COM = "ex.com.";
    public bool IsReusable { get { return false; } }
}

现在,您只需要在相同目录中有备用文件。例如:

/Images/logo.jpg

/Images/v2.logo.jpg

/Styles/mystyle.css

/Styles/v2.mystyle.css

我希望这会有所帮助:)

【讨论】:

  • 但真正的问题是确定要实际写入流的文件。两种情况下 Http_referrer 都指向同一个 URL
  • 在这种情况下,可以使用 Request.UrlReferrer 代替上面的 HttpRequest.Url。问题中的更新说“因此,如果引用 url 是 intranet,它应该继续调用旧样式表。如果引用 url 是 intranetv2,它应该调用新样式表。”这意味着推荐人不同。
  • 或者在请求样式表时,OP 对引用者的假设存在错误。引用标头是嵌入 css 标签的文档,而不是搜索页面。 IE 在referer 中没有任何信息可用于根据单击新旧搜索页面上的链接来确定该页面是否被请求
  • +1 - 尽管 OP 写道,每个搜索都会有不同的引荐来源网址,但似乎这并不正确 - 超出了第一页。根据初始搜索引荐来源设置 cookie 并使用它可能比每次检查引荐来源更好。
  • 希望 OP 能够向我们通报他的工作方式。知道问题是如何解决的总是好的。
【解决方案2】:

是的,您应该能够在“旧”应用程序上使用 HttpModule 来拦截对旧 CSS 的调用。 根据您服务器上的 IIS 版本,您可能需要进行一些配置以确保 .NET 正在处理对 .css 文件的调用,否则您的 HttpModule 将不会被调用。 参考this question

一旦 .NET 处理对 CSS 的调用,您就可以动态地动态切换 css,以防请求是针对“旧”css 文件的。

这是一篇旧文章(因为您使用的是 .NET 1.1),它应该为您指明 IIS 的实现和配置的正确方向:"URL Rewriting in ASP.NET"。基本上你所做的非常相似,因为你正在“重写”一个特定的 URL(旧 CSS 文件的那个)以指向不同的内容。

【讨论】:

  • @oshirowanen:我认为在这种情况下,您应该配置 IIS 以让 .NET 处理 css 文件。我发布的链接应该指向你如何做到这一点的说明。
  • 在拦截对 css 文件的请求时,我认为 http_referer 标头将指向链接/导入它的内容页面,而不是链接到内容页面的搜索结果页面。所以即使搜索结果在http://intranetv2,在css文件请求期间Request.ServerVariables["HTTP_REFERER']也会是http://intranet,你会继续得到旧的css文件。
  • @wonkim00 我认为你是对的。 Oshirowanen 可能应该使用其他东西(例如查询字符串中的附加参数)来区分来自旧搜索引擎和来自新搜索引擎的调用。流程是:新的搜索引擎将“&newsearch=1”(或类似的)附加到“intranet”结果的 url; httpmodule 检查 url 并设置,例如,为从新引擎搜索的人设置会话 cookie;当调用“旧”css 时,如果设置了会话 cookie,则会提供新的 css。
【解决方案3】:

基于域名,您可以从后面的代码(.vb或.cs文件甚至一个类)动态控制页面的一部分。这将使您能够控制根据域名替换 css 文件。捕获代码中的域名然后替换css文件/链接,实际上整个部分都在后面的代码中。 您可以在 C# 或 VB 中执行此操作。

【讨论】:

    【解决方案4】:

    我不建议使用httpModule,因为每个请求都会调用它,这可能会降低性能。而您可以使用 httpHandlers 仅处理特定路径。因此,我的投票是使用httpHandlers

    但是有一个小故障。默认情况下,IIS 6 默认不会将非 ASP.Net 扩展(读取 .aspx、.ashx、.axd 等其他扩展)的请求传递给 ASP.Net。

    因此,您需要为 CSS 扩展添加 ISAPI 模块,以将请求传递给 aspnet_isapi.dll(您可以从 .aspx 扩展处理程序中找到完整路径)。

    这个link 可能有助于设置 ISAPI 模块。

    一旦 ASP.Net 开始处理 .CSS 扩展,请使用您的逻辑编写 httpHandler 并在 web.config 文件的 httphandlers 部分下添加以下行

    假设您的 httpHandler 是 CSSHttpHandler,那么代码将是这样的。

    <add verb="HEAD,GET" path="*.css" type="CSSHttpHandler">
    

    希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      我对我们的内容管理系统提供的文件做了一些类似的事情。如果打开了 http 处理程序,它会检查文件名和路径以查看用户是否有权访问资源。如果用户这样做,它会流式传输文件,否则返回 401 not authorized。

      我不明白为什么您不能使用处理程序来跳转到 css 文件的管道、检查主机名并转而输出其他 css 文件(如果适用)。这在带有集成管道的 IIS7 中很简单(您没有指定),但如果您让 .net 处理 css 扩展名,则在 IIS6 中也是可能的。

      如果您对这种方法感兴趣,请告诉我,我会追踪一些代码。

      编辑 - 这是一些代码

      这并不是您想要的,但您可能会得到一些想法。

      注意:这是在带有集成管道的 IIS7 中,因此在 IIS6 中您必须进行更改,以便 .net 进程处理 .css 文件。

      Public Class FileManagerFileAuthorization
          Implements IHttpHandler
      
          Public ReadOnly Property IsReusable As Boolean Implements System.Web.IHttpHandler.IsReusable
              Get
                  Return True
              End Get
          End Property
      
          Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
      
              Dim req As HttpRequest = context.Request
              Dim absolutePath As String = req.Path
              Dim fileName As String = Path.GetFileName(absolutePath)
              Dim physicalPathAndFileName As String = HttpContext.Current.Server.MapPath(absolutePath)
      
              If File.Exists(physicalPathAndFileName) Then
      
                  ' roles that the user is part of. If the user is not authenticated they are part of the public role only
                  Dim memberRoles As String()
                  If req.IsAuthenticated = False Then
                      memberRoles = New String() {ConfigurationManager.AppSettings("PublicRole")}
                  Else
                      Dim r As New Roles()
                      memberRoles = r.GetRolesForUser("")
                  End If
      
                  ' check permissions: transmit file or deliver 401
                  Dim folderVirtualPath As String = Path.GetDirectoryName(absolutePath).Replace("\"c, "/"c)
                  Dim permissions As FileManager.FolderPermissions = FileManager.GetFolderPermissions(folderVirtualPath, memberRoles)
                  If permissions And FileManager.FolderPermissions.View Then
                      context.Response.ContentType = FileManager.GetContentType(fileName)
                      context.Response.AddHeader("Content-Length", New FileInfo(physicalPathAndFileName).Length.ToString())
                      context.Response.TransmitFile(physicalPathAndFileName)
                  Else
                      ' unauthorized
                      context.Response.StatusCode = 401
                  End If
      
              Else
                  ' file not found
                  context.Response.StatusCode = 404
              End If
      
              context.Response.End()
      
          End Sub
      
      End Class
      

      还有 web.config - 再一次 - 这是 IIS7,因此您将使用 system.web 部分下的 &lt;httpHandlers/&gt; 部分。我正在查找 Userfiles 目录中的任何文件,但我认为您可以直接指向包含此文件的文件。

      <system.webServer>
        <handlers>
          <add name="FileManagerFileAuthorization" path="Userfiles*" verb="GET" type="FileManagerFileAuthorization" resourceType="Unspecified" preCondition="integratedMode" />
        </handlers>
      </system.webServer>
      

      注意:

      要允许 .net 处理 IIS 中的非 .net 文件,您必须允许 .net 进程处理这些文件。为此,请打开 IIS 管理器,导航到该网站,然后单击属性。转到“主目录”选项卡,然后单击“配置”。添加通配符映射,然后选择 .net dll。如果您不确定,请从下面的 .ascx 复制链接。

      由于是 IIS6,您将无法使用上面的 system.webServer 部分,您需要以旧方式添加 http 处理程序。这个链接解释它:http://msdn.microsoft.com/en-us/library/46c5ddfy.aspx

      【讨论】:

      • 我正在使用 IIS6。任何代码、指南、教程都会很棒!
      • 我看到很多响应都表明一个 httpmodule。我认为处理程序是一种更好的方法,因为我们处理的是实际文件,而不是请求。这是一个很好的概述:msdn.microsoft.com/en-us/library/bb398986.aspx
      • 使用 httphandler (如果我没有误解你的建议)将意味着更改旧域中的所有 10000 多个页面,以便它们引用处理程序而不是引用 css 文件,而不是(反过来应该提供正确的 css 文件)。我认为这不是@oshirowanen 想要做的事情
      • HTTP 处理程序听起来不错,但如果这意味着必须更新旧域上的所有 10,000 多个页面,正如 ScottE 刚刚提到的,那么我将无法将其视为一个选项。但是,如果可以在不更新所有旧页面的情况下完成,请告诉我。
      • 我建议您监听正在提供的 css 文件,如果域不匹配,则改为提供另一个。因此,在我的示例中,如果某些条件不匹配,则不会发出 401,而是传输不同的 css 文件。
      【解决方案6】:

      也许您可以在旧域上添加一个 HTTP 模块并检查 request.UrlReferrer 是否是来自新域的搜索结果页面,然后在生成的输出中替换旧样式表的链接。

      【讨论】:

      • 你知道分步指南,我可以按照教程来完成这项工作吗?
      【解决方案7】:

      正如我在评论中所述:one of the answers,我认为 http_referer 标头将指向链接/导入请求的 css 文件的内容页面,而不是链接到内容页面的搜索结果页面。所以即使搜索结果在http://intranetv2,css文件请求期间的Request.ServerVariables["HTTP_REFERER']也会是http://intranet,你会继续得到旧的css文件。

      似乎您必须想办法从新的http://intranetv2 域中提供 10000 个内容页面,或者想出一种在内容 aspx 页面请求期间设置标志的方法(可能在全局.asax Application_BeginRequest),可以在 css 文件请求期间读取和操作(通过 HttpHandler,就像其他人建议的那样)。

      但不确定适当的信号机制是什么。它需要为每个用户而不是每个应用程序工作,并且在多个不同的文件请求期间可用并持续存在,并且选择受到使用 .NET 1.1 的限制。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-24
        • 2014-10-23
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多