Domanda

90% of the pages on my website follows this syntax

http://www.thisismysite.com/ShowProduct.aspx?ID=29
http://www.thisismysite.com/BrowseProducts.aspx?CatID=58

I was checking Google webmaster tools and saw that my site is generating errors for the following url's

http://www.thisismysite.com/ShowProduct.aspx%20ID=50
http://www.thisismysite.com/BrowseProducts.aspx%20CatID=58
http://www.thisismysite.com/ShowProduct.aspx%3FID%3D900
http://www.thisismysite.com/ShowProduct.aspx%3FID=727
http://www.thisismysite.com/ShowProduct.aspx%3FID=64
http://www.thisismysite.com/GetProductsRss.aspx%3FCatID%3D60

When I browsed these url's, I got the error

Server Error in '/' Application.

Runtime Error Description: An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.

How can I fix these errors? I know about the relaxedUrlToFileSystemMapping="true" but isn't that a hack? What's the proper way to handle these url's

A portion of my web.config looks like this

<system.web>
<httpRuntime requestValidationMode="2.0" />
<authentication mode="Forms">
    <forms cookieless="UseCookies" loginUrl="~/AccessDenied.aspx" name="TBFORMAUTH" />
</authentication>
<pages theme="TemplateM" masterPageFile="~/Template.master"   maintainScrollPositionOnPostBack="false" validateRequest="false"   enableEventValidation="false" viewStateEncryptionMode="Never"   controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">  
</pages>
<!--
Possible modes are "transitional", "strict", and "legacy".
<xhtmlConformance mode="transitional" />
-->
<compilation debug="false" targetFramework="4.0">           
    <assemblies>
        <add assembly="System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C53R34E089" /></assemblies></compilation>


<sessionState mode="InProc" cookieless="false" timeout="15" />
<roleManager enabled="true" cacheRolesInCookie="true" cookieName="TBROLES" defaultProvider="TB_RoleProvider">
    <providers>
        <add connectionStringName="LocalSqlServer" applicationName="/" name="TB_RoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f22f50a3a" />
    </providers>
</roleManager>
<anonymousIdentification cookieless="UseCookies" enabled="false" />
<profile defaultProvider="TB_ProfileProvider">
    <providers>
        <add name="TB_ProfileProvider" connectionStringName="LocalSqlServer" applicationName="/" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f64f1d50a3a" />
    </providers>
    <properties>
        <add name="FirstName" type="String" />
        <add name="LastName" type="String" />
        <add name="Gender" type="String" />
        <add name="BirthDate" type="DateTime" />
        <add name="Occupation" type="String" />
        <add name="Website" type="String" />

        <group name="Forum">
            <add name="Posts" type="Int32" />
            <add name="AvatarUrl" type="String" />
            <add name="Signature" type="String" />
        </group>
        <group name="Address">
            <add name="Street" type="String" />
            <add name="PostalCode" type="String" />
            <add name="City" type="String" />
            <add name="State" type="String" />
            <add name="Country" type="String" />
        </group>
        <group name="Contacts">
            <add name="Phone" type="String" />
            <add name="Fax" type="String" />
        </group>
        <group name="Preferences">
            <add name="Theme" type="String" allowAnonymous="false" />
            <add name="Culture" type="String" defaultValue="en-US" />
        </group>
    </properties>
</profile>
<webParts enableExport="true">
    <personalization defaultProvider="TB_PersonalizationProvider">
        <providers>
            <add name="TB_PersonalizationProvider" connectionStringName="LocalSqlServer" type="System.Web.UI.WebControls.WebParts.SqlPersonalizationProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        </providers>
        <authorization>
            <allow roles="Administrators,Editors" verbs="enterSharedScope" />
        </authorization>
    </personalization>
</webParts>
<machineKey validationKey="287C5D125D6B7E7223E1F719E3D58D17BB9677030175D6B7E7223E1F719E3D58D17BBC7E59800B5D4C2EDD5B5D6B7E7223E1F719E3D58D17BBBAF260D9D374A74C76CB741803" decryptionKey="5C1D8BD9DF3E1B4E1D05C1D8BD9DF616E0D5C1D8BD9DF" validation="SHA1" />

<customErrors defaultRedirect="~/Error.aspx" redirectMode="ResponseRewrite">
</customErrors>

<urlMappings>
    <add url="~/articles/beer.aspx" mappedUrl="~/BrowseProducts.aspx?CatID=28" />
    <add url="~/articles/events.aspx" mappedUrl="~/BrowseProducts.aspx?CatID=41" />
    <add url="~/articles/news.aspx" mappedUrl="~/BrowseProducts.aspx?CatID=31" />
    <add url="~/articles/photos.aspx" mappedUrl="~/BrowseProducts.aspx?CatID=40" />
    <add url="~/articles/blog.aspx" mappedUrl="~/BrowseProducts.aspx?CatID=29" />
    <add url="~/articles/faq.aspx" mappedUrl="~/BrowseProducts.aspx?CatID=42" />
</urlMappings>
<healthMonitoring heartbeatInterval="10800">
    <providers>
        <remove name="SqlWebEventProvider" />
        <add name="SqlWebEventProvider" connectionStringName="LocalSqlServer" buffer="false" bufferMode="Notification" maxEventDetailsLength="1073741823" type="System.Web.Management.SqlWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7fse350a3a" />
    </providers>
    <eventMappings>
        <add name="TB Events" type="MB.Customs.WebCustomEvent, MB.Customs.CustomEvents" />
    </eventMappings>
    <rules>
        <clear />
        <add name="TB Events" eventName="TB Events" provider="SqlWebEventProvider" profile="Critical" />
        <add name="All Errors" eventName="All Errors" provider="SqlWebEventProvider" profile="Critical" />
        <add name="Failure Audits" eventName="Failure Audits" provider="SqlWebEventProvider" profile="Critical" />
        <add name="Heartbeats" eventName="Heartbeats" provider="SqlWebEventProvider" profile="Critical" />
    </rules>
</healthMonitoring>
</system.web>
È stato utile?

Soluzione

Because these external links are URL encoded, ASP.NET will try to find files or routes with that name. You could try messing around with the routing framework to be smart about looking for URLs that start with the routes in your application. However, this would probably mean each page needs additional logic within them to parse the improperly encoded requests. Another solution is to add custom error handling for the 404 that ASP.NET will generate when you know how to best redirect the user.

Probably the best way you could handle this error would be to intercept errors in your Applications Global.asax.cs file. You could try something like the following in your Application_Error method:

protected void Application_Error(Object sender, EventArgs e) 
{
    bool httpError = Context.Error is HttpException;
    if (httpError && ((HttpException)Context.Error).GetHttpCode() == 404)
    {
        // Convert the path to lowercase. This should ONLY be used to make finding indices easier, but NOT used when generating the redirect path since case could be important.
        string absolutePath = Request.Url.AbsolutePath.ToLowerInvariant();
        int extensionLength = ".aspx".Length;
        int questionMarkIdx = absolutePath.IndexOf("?");
        int encodedQuestionMarkIdx = absolutePath.IndexOf(".aspx%3F") + extensionLength;
        int encodedSpaceIdx = absolutePath.IndexOf(".aspx%20") + extensionLength;
        // Handle encoded question mark
        if ((questionMarkIdx == -1) && (encodedQuestionMarkIdx > extensionLength))
        {
            string correctPath = Request.Url.AbsolutePath.Substring(0, absolutePath.Length - encodedQuestionMarkIdx);
            // Add 3 here to exclude the "%3F" in the result
            string encodedQueryString = Request.Url.AbsolutePath.Substring(encodedQuestionMarkIdx + 3);
            Response.Redirect(correctPath + "?" + HttpUtility.UrlDecode(encodedQueryString));
        }
        // Handle encoded space
        if ((questionMarkIdx == -1) && (encodedSpaceIdx > extensionLength))
        {
            string correctPath = Request.Url.AbsolutePath.Substring(0, absolutePath.Length - encodedSpaceIdx);
            // Add 3 here to exclude the "%20" in the result
            string encodedQueryString = Request.Url.AbsolutePath.Substring(encodedSpaceIdx + 3);
            Response.Redirect(correctPath + "?" + HttpUtility.UrlDecode(encodedQueryString));
        }
    }
}

I wrote this answer on a non-Windows machine, so I don't have a way to test it but this should be enough to get you in the general direction you should go in solving this problem.

The important point is to make a distinction between 404s that happened because the URL was improperly encoded and 404s that happened because of some other generic reason you're unable to handle. You only want to handle 404s due to URL encoding issues. All other errors and other 404 messages should be propagated back to your default handlers.

Also an important thing to check is what the referrer is on these requests to bad URLs. You should look in Google Webmaster tools to see if they tell you. If they don't you need to check your logs (or ensure you make some!) to find out where they're coming from. Once you know the source you should contact the site owner to let them know they're serving out bad URLs. Trying to compensate for broken external links is not foolproof and is a very difficult challenge that can become a full-time job on its own, so you're best off trying to stop them from being generated in the first place if it's within your power to make it happen.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top