Extra information in URL redirecting from nolayout.aspx to 404 error page in sitecore website - indexing

I just moved my nolayout.aspx to 404 error page inside config file, everything is working fine except the URL. After getting redirect to 404 URL has these extra information :
404?item=%2fservices-and-solutions%2fbusiness-vision%2fit-without-boundaries&layout={00000000-0000-0000-0000-000000000000}&device=Default
I dont want URL having this : &layout={00000000-0000-0000-0000-000000000000}&device=Default
Config settings is :
Rest is fine for me, kindly suggest.

That URL is generated from sitecore. It's not IIS. This one you are getting is when the item doesn't have a layout set. You might also want to look at the not found url. You can set these urls to point to sitecore items in web.config:
Unfortunately, sitecore does not return a Not found status code, so it is better to create your own handler to read the Item and set the status code. See an example here from RUUD VAN FALIER: http://www.partechit.nl/en/blog/2012/11/return-404-status-code-when-itemnotfound-page-is-loaded
Basically, you append a processor after Sitecore.Pipelines.HttpRequest.ExecuteRequest and override RedirectOnItemNotFound and the RedirectOnLayoutNotFound as necessary.

I think you just need to add an additional section to <system.webServer> in your web.config.
<httpErrors errorMode="Custom">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/404" responseMode="ExecuteURL" />
</httpErrors>
As well as setting RequestErrors.UseServerSideRedirect to true.
Reference: http://herskind.co.uk/blog/2012/03/sitecore-404-without-302

Also you can add existingResponse="PassThrough" along with erroMode
Check detailed explanantion at: IIS httpErrors

Thanks guys, Surely I am going to try all the suggestion given above and will see which one is working finest with this case.
Right now I just implemented a code in my redirect module with every time of querystring appending on sitecore URL's
`Defined a baseURL using Sitecore.Links.LinkManager.GetItemUrl(Sitecore.Context.Item);
if (baseUrl.ToLower().Contains("?"))
{
ReqUrl = baseUrl;
baseUrl = ReqUrl.Substring(0, ReqUrl.IndexOf("?"));
AppendedUrl = ReqUrl.Substring(baseUrl.Length);
}
string Qurl = Request.RawUrl;
if (Qurl.ToLower().Contains("?"))
{
Qurl = Request.RawUrl.Substring(0, Request.RawUrl.IndexOf("?"));
AppendedUrl = Request.RawUrl.Substring(Qurl.Length);
}
if (Qurl.ToLower().EndsWith("/"))
{
baseUrl = baseUrl + "/";
}
//Code for URLEncoding
string fullPath = baseUrl + AppendedUrl;
fullPath = System.Web.HttpUtility.UrlDecode(fullPath);
if (fullPath.ToLower().Contains("&layout"))
{
fullPath = Request.RawUrl.Substring(0, Request.RawUrl.IndexOf("&layout"));
}
if (baseUrl.ToLower() != Qurl.ToLower())
{
Response.RedirectPermanent(fullPath);
}
}
}`
so URL encoding and putting condition with types of querystring exist in website resolved my problem.
Thanks again for ideas, I am going to see alternate ways too from them.

Related

Cypress: Check current URL

I am trying to get URL which I am getting after redirection if do following:
cy.url().then(url => {
cy.log(url);
});
Then I get logged initial URL, but not the (new url), how do I get url in cypress after redirection?
redirection img (new url)
Solution:
To get the redirected URL just simply add cy.get and your element so it will wait until the redirect page loads. Here is the working solution for me:
cy.get('.crumb > p')
cy.url().then(url => {
cy.log(url);
});
Exactly as you wrote, you need to first wait for a element from the new URL to be visible, using a cy.get('any-element-from-the-new-url').
After that you can get the new URL just using cy.url(), in this case if you want to log this URL you can just use cy.log(cy.url()).
A more meaningful approach would be to add an assertion on the pathname to what you are expecting. The docs can shed some light on the cy.location(). You can use an include assertion on the pathname in the situation that you will not know all of the url string.
// visiting url - https://website.com/favorites
// redirects to - https://website.com/favorites/regional/local
cy.location('pathname') // yields "/favorites/regional/local"
.should('include', '/favorites/')
.then(cy.log)
If you do this, you don't have to do any previous step. Especially because the expectedUrl doesn't have to match the actual url which allow your test doesn't crash if that happens.
cy.url('match', 'expectedUrl').then(el=>{
cy.log(el)
})

how to get browser full url of the page in nodejs express in environment, seems nginx issue?

I am using a url rewriting functionality in my application(SparatcusV3.4).
I am calling my backend from node js to check a productcode exists or not
for that I need the current browser url entered by user in the address bar.
I am accessing the url using below code
const fullUrl = req.protocol + '://' + req.get('host')
this is working fine on my local system but when deployed on any environment(by SAP)
this URL is coming as "127.0.0.1:4200" , what might be the problem here with environment ?
or what is the correct way to get the full browser url entered by the user ?
any help would be appreciated!!!
thanks in advance
Please refer to this part of Spartacus docs: https://sap.github.io/spartacus-docs/server-side-rendering-coding-guidelines/#getting-the-request-url-and-origin
It suggests to use SERVER_REQUEST_URL and SERVER_REQUEST_ORIGIN injection tokens when using the setup that's running SSR behind a proxy in order to resolve URLs.
To use these optional tokens:
it is assumed you're using Spartacus' NgExpressEngineDecorator from #spartacus/setup/ssr in your server.ts file.
when injecting them, you should mark them as #Optional (per docs), as these are not available in CSR application.
const obj = {};
const rc = request.headers.cookie;
rc?.split(';')?.forEach((cookie: any) => {
const parts = cookie?.split('=');
obj[parts.shift().trim()] = decodeURI(parts?.join('='));
});
return obj;
it can give list of all cookies in request object so with OBJ['RT'] can give the value and further splitting with '=' we cna get the exact request URL there from we can extract the host and the origin uding below code
const cookieName = 'RT';
const cookieObj = this.getCookieasObject(req);
let fullURL = cookieObj[cookieName];
if (fullURL) {
fullURL = decodeURIComponent(JSON.parse(fullURL).split('=')[1]);
}
const url = new URL(fullURL);
const baseUrl = `${url.protocol}//${url.hostname}`;

Page can't be found error and not hitting my app while url contains like .vpf,.html (dot extensions)

If I am using an url like '**' it goes to the error page. But, my application is not getting hit while giving url like '.vpf' or '.vd'. How can I fix it?
What are you using for your web server? IIS?
You need to add Handler Mappings for those file types that you want to serve; note that IIS will have defaults for .htm, .axd, etc, but not other types, like .vpf.
Try requesting those files directly in the browser (not via javascript) and running Fiddler at the same time, and you should get more information about what is and isn't happening.
added route with constraints in startup.cs
routes.MapRoute(
name: "xxx",
template: "{xx}/{yy}/{*zz}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { xx= #"^[a-zA-Z0-9]+$", yy= #"^[a-zA-Z0-9]+$", zz= #"(.*?)\.(vpf)" }
);
Its working for .vpf

Force reload cached image with same url after dynamic DOM change

I'm developping an angular2 application (single page application). My page is never "reloaded", but it's content changes according to user interactions.
I'm having some cache problems especially with images.
Context :
My page contains an editable image list :
<ul>
<li><img src="myImageController/1">Edit</li>
<li><img src="myImageController/2">Edit</li>
<li><img src="myImageController/3">Edit</li>
</ul>
When i want to edit an image (Edit link), my dom content is completly changed to show another angular component with a fileupload component.
The myImageController returns the LastModified header, and cache-control : no-cache and must-revalidate.
After a refresh (hit F5), my page does a request to get all img src, which is correct : if image has been modified, it is downloaded, if not, i just get a 304 which is fine.
Note : my images are stored in database as blob fields.
Problem :
When my page content is dynamically reloaded with my single page app, containing img tags, the browser do not call a GET http request, but immediatly take image from cache. I assume this a browser optimization to avoid getting the same resource on the same page multiple times.
Wrong solutions :
The first solution is to add something like ?time=(new Date()).getTime() to generate unique urls and avoid browser cache. This won't send the If-Modified-Since header in the request, and i will download my image every time completly.
Do a "real" refresh : the first page load in angular apps is quite slow, and i don't to refresh all.
Tests
To simplify the problem, i trying to create a static html page containing 3 images with the exact same link to my controller : /myImageController/1. With the chrome developper tool, i can see that only one get request is called. If i manage to get mulitple server calls in this case, it would probably solve my problem.
Thank you for your help.
5th version of HTML specification describes this behavior. Browser may reuse images regardless of cache related HTTP headers. Check this answer for more information. You probably need to use XMLHttpRequest and blobs. In this case you also need to consider Same-origin policy.
You can use following function to make sure user agent performs every request:
var downloadImage = function ( imgNode, url ) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "blob";
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status == 304) {
var blobUrl = URL.createObjectURL(xhr.response);
imgNode.src = blobUrl;
// You can also use imgNode.onload callback to release blob resources.
setTimeout(function () {
URL.revokeObjectURL(blobUrl);
}, 1000);
}
}
};
xhr.send();
};
For more information check New Tricks in XMLHttpRequest2 article by Eric Bidelman, Working with files in JavaScript, Part 4: Object URLs article by Nicholas C. Zakas and URL.createObjectURL() MDN page and Same-origin policy MDN page.
You can use the random ID trick. This changes the URL so that the browser reloads the image. Not that this can be done in the query parameters to force a full cache break or in the hash to allow the browser to re-validate the image from the cache (and avoid re-downloading it if unchanged).
function reloadWithCache(img: HTMLImageElement, url: string) {
img.src = url.replace(/#.*/, "") + "#" + Math.random();
}
function reloadBypassCache(img: HTMLImageElement, url: string) {
let sep = img.indexOf("?") == -1? "?" : "&";
img.src = url + sep + "nocache=" + Math.random()
}
Note that if you are using reloadBypassCache regularly you are better off fixing your cache headers. This function will always hit your origin server leading to higher running costs and making CDNs ineffective.

Aurelia Post with http-fetch-client producing an options request

I'm creating a small forum where people in our company can put up adverts for goods or services they want to sell on the fly, using aurelia. I have a list of adverts page working fine, a details page for each advert working fine both using get requests from an api. However i can't seem to get the work the Post reqeust when someone wants to add a comment on an advert.
#inject(HttpClient)
export class ApiData {
constructor(httpClient) {
httpClient.configure(config => {
config
.withBaseUrl("MyUrl");
});
this.http = httpClient;
//.configure(x => {x.withHeader('Content-Type', 'application/json');});
}
postAdvertComment(comment, id) {
return this.http.fetch(`/adverts/${id}/comments`, {
method: "post",
body: json(comment),
headers: {
'Accept': 'application/json'
}
});
}
getAdverts() {
return this.http.fetch("/adverts")
.then(response => {
return this.adverts = response.json();
});
}
getAdvert(id) {
return this.http.fetch(`/adverts/${id}`)
.then(response => {
return this.advert = response.json();
});
}
}
Doing this project we've had some issue with CORS, all solved by adding in AllowCors tags in the api, including all methods etc.
<add key="CorsAllowedOrigins" value="*" />
<add key="CorsAllowedHeaders" value="" />
<add key="CorsAllowedMethods" value="*" />
However when i try and run the post, its running an options method and returns a 400 Bad request.
Here
We also get the following CORS error:
Fetch API cannot load MyURL/api/adverts/2/comments. Response to preflight
request doesn't pass access control check: No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin 'http://localhost:49877' is
therefore not allowed access. The response had HTTP status code 400. If an
opaque response serves your needs, set the request's mode to 'no-cors' to fetch
the resource with CORS disabled.
I don't know if it's a problem with our c# api or with how I'm trying to post from aurelia, but we have tried sending requests from postman and it works fine, tried sending post request within the same app using jquery and it works fine, and all the get requests work fine, but for some reason this post is causing all sorts of problems.
It seems to be a problem in your WebAPI, but before giving you some possible solutions I'd like to show you some important things.
Postman is not affected by CORS, so all requests work.
jQuery ajax uses XHR (XmlHttpRequest object) while aurelia-fetch-client uses fetch (window.fetch. However, the fetch-polyfill uses XHR in the background). They are
different approaches to solve the same problem. Just because one of them work, doesn't actually mean that the other one should work too.
The OPTIONS request is made by fetch, that's how it works. More information here https://developers.google.com/web/updates/2015/03/introduction-to-fetch?hl=en
To solve this problem try to remove those tags from web.config, and allow CORS in your Startup.cs. Like this:
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll); //or another parameter
//rest of your code
}
You don't have to set the content-type header to application/json. It is automatically made when you use the json() function ---> body: json(comment)
If you are using OWIN you might have to send the content-type as x-www-form-urlenconded. In that case, take a look at this Post 'x-www-form-urlencoded' content with aurelia-fetch-client