Custom 404 page in sitecore from content tree - sitecore

I have multilingual website and I want a custom 404 page in all languages which depends on the context of the site. What is the correct approach to get the 404 page defined in content tree or to access 404 page from content tree? I am able to get 404 page if I will define that in my site root but not from content tree.
I want 404page from the content tree as my 404 Custom redirect.
My Webconfig setting:
<setting name="ItemNotFoundUrl" value="/404Page.aspx" />
IIS 404 entry.
The error i got when page is not there in sitecore:
After changing IIS to default and setting httpErrors like
<error statusCode="404" path="/404PAGE.aspx" responseMode="ExecuteURL" />
</httpErrors>

I use a custom implementation of the ExecuteRequest processor in the httpBeginRequest pipeline.
That is where the 404 requests are eventually handled.
You can override the RedirectOnItemNotFound method in there and add some logic to load a different 404 page per site.
Take a look at this blog post that explains how to implement it.
EDIT: I have added an example of how to implement it so you can return a site specific 404 page.
If you make this modification, you can return a different 404 page per site:
Add this to the configuration:
<setting name="NotFoundPage.SiteName1" value="/not-found.aspx" />
<setting name="NotFoundPage.SiteName2" value="/not-found.aspx" />
Then in the custom RedirectOnItemNotFound code, do this to return site specific 404 content:
public class ExecuteRequest : Sitecore.Pipelines.HttpRequest.ExecuteRequest
{
protected override void RedirectOnItemNotFound(string url)
{
var context = System.Web.HttpContext.Current;
try
{
// Get the domain of the current request.
string domain = context.Request.Url.GetComponents(UriComponents.Scheme | UriComponents.Host, UriFormat.Unescaped);
// Get 'not found page' setting for current site.
string notFoundUrl = Sitecore.Configuration.Settings.GetSetting(string.Conact("NotFoundPage.", Sitecore.Context.Site.Name));
// Request the contents of the 'not found' page using a web request.
string content = Sitecore.Web.WebUtil.ExecuteWebPage(string.Concat(domain, notFoundUrl));
// Send the content to the client with a 404 status code
context.Response.TrySkipIisCustomErrors = true;
context.Response.StatusCode = 404;
context.Response.Write(content);
}
catch (Exception)
{
// If our plan fails for any reason, fall back to the base method
base.RedirectOnItemNotFound(url);
}
// Must be outside the try/catch, cause Response.End() throws an exception
context.Response.End();
}
}
The idea is that you use the site name as setting key so you can resolve the configuration value per site.
The code needs some work of course, but you get the idea..
EDIT 2: Added example configuration to replace the original pipeline processor with the new one:
<pipelines>
<httpRequestBegin>
<processor type="Sitecore.Pipelines.HttpRequest.ExecuteRequest, Sitecore.Kernel">
<patch:attribute name="type">ParTech.Pipelines.ExecuteRequest, ParTech</patch:attribute>
</processor>
</httpRequestBegin>
</pipelines>

Sitecore does some of its own "item not found" handling, and also doesn't do a good job of handling 404s in an SEO-friendly manner.
The best solution I've found for handling 404s and other errors in Sitecore is the Sitecore Error Manager.
http://marketplace.sitecore.net/en/Modules/Sitecore_Error_Manager.aspx
https://github.com/unic/SitecoreErrorManager/wiki

You can set ItemNotFoundUrl in Sitecore config to any item in the content tree, it does not need to be in the site root, and as long as you don't specify a language it will use whatever the user has been browsing the site in (or default for first visit). The item has to be in the same tree structure for all sites though:
<setting name="ItemNotFoundUrl" value="/errors/404.aspx" />
<setting name="LayoutNotFoundUrl" value="/errors/500.aspx"/>
<setting name="NoAccessUrl" value="/errors/403.aspx"/>
Techphoria414 is right that Sitecore out of the box does not do a good at handling 404s in an SEO friendly manner, it will do a 302 redirect to the error page. However, if you set the following to true then a Server.Transfer will be used:
<!-- USE SERVER-SIDE REDIRECT FOR REQUEST ERRORS
If true, Sitecore will use Server.Transfer instead of Response.Redirect to redirect request to service pages when an error occurs (item not , access denied etc).
Default value: false
-->
<setting name="RequestErrors.UseServerSideRedirect" value="true"/>
Which triggers the following code in the ExecuteRequest pipeline.
protected virtual void PerformRedirect(string url)
{
if (Settings.RequestErrors.UseServerSideRedirect)
HttpContext.Current.Server.Transfer(url);
else
WebUtil.Redirect(url, false);
}
You can read more about it in this blog post. Be sure to set Status property of the current System.Web.HttpResponse to 404 in your code that handles it. There is more info in the Handling HTTP 404 document.
Error Manager is a great module though and is much more flexible if you need to set different url locations for different sites.

I have written a blog post on this, might be useful for someone in future.
http://sitecoreblog.tools4geeks.com/Blog/35/Better-way-of-handling-sitecore-404-pages
The approach i have taken is :
Add a processor after HttpRequest.ItemResolver on HttpRequestBegin pipeline.
Find if context item is null, if null set 404 content page as context item.
Add another processor in the pipeline httpRequestEnd after EndDiagnostics processor to set the 404 status code for not found Item.
With this approach, we don't need to set 404 status code on Renderings. As we are setting it at the end of "httpRequestEnd" pipeline. /404 page returns 200 status code as this page suppose to return 200 status code.
works in multi-site/multi-language environment.

Related

postman render html response and execute JavaScript

I have an http api that give me html response, and I want to "preview" it.
But there is some javascript code in it, and without execute them, it won't give me the right page.
I currently manually copy & paste them in some aaa.html file and use chrome to open it(file://aaa.html), but I want to simplified those steps.
Is there anyway to do that in postman? or is there any postman alternative can do that?
There is an alternative to do this in Postman itself. You will have to use pm.visualizer. Just open your API request which is giving you the HTML response. Then go to the Test tab, add the lines below, and then click on the Visualize tab:
// save your html response in the template and then
const template = pm.response.text();
// set that template to pm.visualizer
pm.visualizer.set(template);
From Postman official documentation
Postman provides a programmable way to visually represent your request responses. Visualization code added to the Tests for a request will render in the Visualize tab for the response body, alongside the Pretty, Raw, and Preview options.
You need add to the Tests for a request:
var template = pm.response.text();
pm.visualizer.set(template);
and see result on the Visualize tab (after Pretty, Raw, and Preview options).
Postman result HTML with JS and CSS
To fix the error:
Refused to load the image 'file:///C:/some.png' because it violates the following Content Security Policy directive: "img-src http: https: data:".
if the content simply does not find (404 Not Found) it along a similar path 'file:///C:/some.file'
need to add the HTML tag to the section of the response body:
var response = pm.response.text();
var base = '<base href="https://some.domain/">";
var template = response.replace('<head>', '<head>' + base);
pm.visualizer.set(template);
this answer also solves the question in this comment.
For more information:
Postman Visualizing responses
HTML <base> tag in MDN Web Docs

Moved legacy classic asp web site to django app but having trouble with django URL redirect app - old URLs with parameters get 500 error

I moved a 20 year old classic asp web site to a django app recently. Google Search Console is showing 500 errors for tons of very old URLS with parameters like /somefile.asp?ID=1234&name=some-name. Most of these URLS I don't even care about - they are really old but would rather they result in 404 than 500. Some do relate to newer content and in theory I could redirect to new django pages but when I try to redirect them using the django redirect app, the site shows 500 errors - like the ? either stops the pages from ever getting to the redirect middleware or the redirect app doesn't like the "?". How can I redirect these urls so I don't get 500 errors? Is there a way in a view to say:
if the full url path is x
redirect to full url path y
I have looked all over stack overflow and elsewhere and can't find this exact problem or a way to write a view like this. I did try the solution here (exactly) because it seems closest to my issue, but it did not work for me for this exact problem: Django's redirects app doesn't work with URL parameters
An example would be /profiles/?adid=134&v=857
The error with debug true is:
DoesNotExist at /profiles/
BusinessCategory matching query does not exist....
So it is trying to match this URL:
path('<slug:slug>/', views.view_category_list, name='view_category_list'),
before it ever gets to the /?
Relevant view code:
def view_category_list(request, slug):
try:
category_detail = BusinessCategory.objects.get(slug=slug)
except BusinessCategory.DoesNotExist:
category_detail = None
if category_detail:
--code here is all working fine so removed it to get to the issue--
else:
raise Http404
I hoped raising the 404 would call up the redirect app to do its job at redirecting to a specific url but it doesn't - it just shows the custom 404 when debug is False. Anyway, the 404 is better than the 500 for SEO purposes but I still would prefer being able to actually redirect some of the URLs to relevant content.

Alfresco custom login page, No 'login' page type configured - but page auth required it

I'm trying to create a custom login page following this documentaiuon http://docs.alfresco.com/5.0/tasks/dev-extensions-share-tutorials-override-login-page.html and this http://blog.arvixe.com/customize-alfresco-share-login-page/
But I couldn't get it works and the log show this exceptio,:
org.springframework.extensions.surf.exception.PlatformRuntimeException: 03110000 No 'login' page type configured - but page auth required it.
And the page web shows this massages:
server error has occurred.
There are a number of reasons why this could have happened:
You have attempted to access a page that does not exist - check the URL in the address bar.
You have attempted to access a page that is not accessible to you, such as a private Site dashboard.
A valid page has been requested but the server was unable to render it due to an internal error - contact your administrator.<br/>
Here all my config:
share-config-custom.xml
<config evaluator="string-compare" condition="WebFramework">
<web-framework>
<defaults>
<page-type>
<id>login</id>
<page-instance-id>mhg-login</page-instance-id>
</page-type>
</defaults>
</web-framework>
</config>
template/instances/mhg-login.xml
<template-instance>
<template-type>mhg/mhg-login</template-type>
</template-instance>
pages/mhg-login.xml :
<page>
<template-instance>mhg-login</template-instance>
<authentication>none</authentication>
</page>
Looks to me like you've got the wrong path for your template:
If you copy it from here:
https://github.com/teqnology/alfresco-login-reset-share
you'll see that your template/instances/mhg-login.xml is wrongly configured:
the correct template path is /src/main/amp/config/alfresco/web-extension/site-data/template-instances and the content should be the path to your file which in your case should have a mhg folder (mhg/mhg-login) which I don't see in your details.
Make sure you create the correct path, and you point it to the correct file.
Cheers

How do I set the Sitecore 8 default login redirect /start page?

Maybe I've just run out of my Google mojo, but I can't figure this out:
In Sitecore 8 user settings, I can set a "Start URL" per user - in other words the page/url, which the user gets directed to after login success. The interface for setting this value looks like this:
If I click off Desktop and hit save, the value of the StartUrl field is set to /sitecore/shell/default.aspx and the user gets redirected to the classic "Lighthouse" desktop.
If I click off Content Editor and hit save, the value of the StartUrl field is set to /sitecore/shell/applications/clientusesoswindows.aspx and the user gets redirected to the content editor, effectively /sitecore/shell/Applications/Content editor.aspx (an extra redirect occurs).
If I click off Default and hit save, the value of the StartUrl field is set to the empty string, and the user gets redirected to the Launchpad thing, effectively /sitecore/shell/sitecore/client/Applications/Launchpad.aspx.
My question is: How do I change the default behaviour, i.e. how do I decide where the user is redirected to, if he or she chooses Default? I want them to go to the Content Editor per default, they don't really fancy the Launchpad.
When you select default in the user manager, it effectively sets the user profile StartUrl value to empty. That just directs the user to /sitecore on your site after they login.
/sitecore has a 302 redirect to the launch pad. I haven't worked out where that is set yet.
An option would be to customize the loggingin pipeline. The default setup for that is:
<loggingin argsType="Sitecore.Pipelines.LoggingIn.LoggingInArgs">
<processor mode="on" type="Sitecore.Pipelines.LoggingIn.ClearCache, Sitecore.Kernel" />
<processor mode="on" type="Sitecore.Pipelines.LoggingIn.CheckClientUser, Sitecore.Kernel" />
<processor mode="on" type="Sitecore.Pipelines.LoggingIn.CheckStartUrl, Sitecore.Kernel" />
</loggingin>
You could add a new processor in instead the CheckStartUrl processor and if the StartUrl is empty, update it to your default from a setting etc...
Something like this*:
public class CustomCheckStartUrl : CheckStartUrl
{
protected override bool ValidateStartUrl(LoggingInArgs args)
{
var isValid = base.ValidateStartUrl(args);
// override the default start url
if (string.IsNullOrWhiteSpace(args.StartUrl))
{
args.StartUrl = Sitecore.Configuration.Settings.GetSetting("MyDefaultStartPage", string.Empty);
}
return isValid;
}
}
And patch that into the pipeline.
*untested code

Determining if a page is a static .aspx page or does not exist in the sitecore pipeline

I'm working in the Sitecore pipeline on a processor. I need to determine if a request being sent is for a static .aspx page that does not have a context item or if the page being requested does not exist.
This will happen right after the ItemResolver process fires so the database is set to master for both an .aspx running through the pipeline and a request for a page that doesn't exist.
I can't check if the Context.Item == null because the static page has no item associated with it and I'd like to keep it that way since the content on said page will not be changing.
Let me know if you have any ideas to differentiate between these!
You might be able to use Sitecore.Context.Page.FilePath. It will be set to your Layout on a Sitecore item (i.e. '/layouts/standard layout.aspx') while on a static page it'll be the path to your page.
If your static pages are all in a different location from your Sitecore layouts it might be as easy as just matching part of the FilePath.
I think you partially answered your own question.
If you put a component in the httpBeginRequest pipeline after ItemResolver, you should be able to check if Context.Item == null. If it is null, then you know the URL doesn't resolve to a Sitecore item. At that point you can use HttpContext.Current.Server.MapPath() to see if it resolves to a path. If it does, then you know it's a static .aspx file. Something like:
public class CheckPath : HttpRequestProcessor
{
public override void Process(HttpRequestArgs args)
{
if (Sitecore.Context.Item == null)
{
if (args.Context.Server.MapPath(args.Context.Request.RawUrl) == null)
{
// 404
}
else
{
// Static
}
}
else
{
// Sitecore item
}
}
}
Patch this into the httpBeginRequest Pipeline:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<httpRequestBegin>
<processor patch:after="*[#type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" type="MyNamespace.CheckPath, MyAssemblyName" />
</httpRequestBegin>
</pipelines>
</sitecore>
</configuration>