For a web service I'm working on, we're using varnish to map "user friendly" URLs to the longer URL where the page is actually located. So for example:
real URL: https://example.com/stuff/things/page.php
user-friendly URL: https://example.com/page
So the way we're achieving this in vcl is as follows:
if (req.url ~ "page") {
set req.url = stuff/things/page.php
}
But now I'm running into a problem in which the query string is getting wiped out in the process. So something to the effect of https://example.com/page?username=Ataraxia just gets mapped to https://example.com/stuff/things/page.php, but I need the query string to pass through to the mapped URL. Does anyone know how I could achieve this through varnish? I'm thinking I'll need to extract the query string via a regex operation and append it to the mapped URL, but I'm new to vcl and am unsure if this is possible, or if there's a better way to do it.
I did not test it but this might do the job:
if (req.url ~ "page") {
set req.url = "/stuff/things/page.php" + regsub(req.url, "[^?]*", "");
}
This is what i do, and works like a charm, i know this is 2 years later response, but might help someone.
if (req.url ~ "page") {
set req.url = regsub(req.url, "page", "stuff/things/page.php\1");
}
Related
I think I solved the first part where it shouldn't cache pages with query parameters using
if ( bereq.url ~ "/\?.*$" ){
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
However, that doesn't show the cached version of the original page when visiting the page with queries.
Any advice is appreciated. Thanks.
What should be added to the varnish-vcl configuration to make this possible?
Sorry, I'm not sure what you need. Your code is actually leveraging the hit-for-miss capabilities of varnish, but you'd be better of just doing this:
sub vcl_recv {
if (req.url ~ \?) {
return (pass);
}
}
The subtle difference in your version, Varnish creates a cache object (just the metadata, actually) for 120 seconds to remember it shouldn't be cached. But as you know from the start you shouldn't cache it, you can just return (pass) in vcl_recv.
Now, if what you want is stripping the query string so that all requests actually return the main page, you have to do this instead:
sub vcl_recv {
set req.url = reqsub(req.url, "\?.*", "");
}
this finds the first question mark and everything right of it and replaces it with nothing, effectively killing the query string.
Hi I want to change my current product URL structure to a new one but I want to keep my old ones working because of people who have linked to my products.
How can I do this without manually creating a 301 redirect for each product?
Not sure what Prestashop version you have, just tried in a 1.6.1.6
You can you this override:
<?php
class Dispatcher extends DispatcherCore
{
protected function loadRoutes($id_shop = null)
{
parent::loadRoutes($id_shop);
$language_ids = Language::getIDs();
if (isset($context->language) && !in_array($context->language->id, $language_ids)) {
$language_ids[] = (int)$context->language->id;
}
foreach ($language_ids as $id_lang) {
foreach ($this->default_routes as $id => $route) {
if($id == "product_rule")
$this->addRoute(
'product_rule2',
'{id}-{rewrite}{-:ean13}.xhtml',
'product',
$id_lang,
$route['keywords'],
isset($route['params']) ? $route['params'] : array(),
$id_shop
);
}
}
}
}
In this case I used a second rule for xhtml (without this override it gave a 404). You can change {id}-{rewrite}{-:ean13}.xhtml to the rule you have, then change the rules in SEO to want you want the new one to be.
Please write your ps version. If you use 1.5 or above?
Do you use this structure now {category:/}{id}-{rewrite}{-:ean13}.html ? or
{category:/}{rewrite}{-:ean13}.html or this {category:/}{rewrite}.html
please write more details
depends on it just make htaccess rule
([0-9]+) for id
(.*) for rewrite
and please use RedirectMatch permanent
and set to the result by $1, $2, etc
that guide must help to understand the htaccess url rewriting https://www.addedbytes.com/articles/for-beginners/url-rewriting-for-beginners/
I'm not able to use an htaccess for my project therefore clean URLs doesn't work for routing. Is there a way to to use query params instead?
example
myf3project.net/user/show isn't possible. Instead I want to do something like this:
myf3project.net?path=user/show or
myf3project.net?view=user&action=show
You can also overwrite the $_SERVER['REQUEST_URI'] for this purpose:
$f3->route('GET /user', function ($f3) { echo "user"; });
$f3->route('GET /user/#action',function($f3,$params){
echo "user->".$params['action'];
});
if ($f3->exists('GET.path',$path))
$f3->URI = $f3->BASE.'/'.$path;
$f3->run();
and then just open
http://myf3project.net?path=user/show
Do you mean that mod_rewrite is not available? That's a problem indeed. You can however call $f3->mock to the rescue.
Here's a quick example:
$f3 = require('lib/base.php');
// Homepage
$f3->route('GET /',function($f3){
echo 'This is home. '.
'Click here to see the contact form.';
});
// Contact form
$f3->route('GET|POST /contact',function($f3){
echo 'This is the contact form. '.
'Click here to go back home.'.
'<form method="post" action="">'.
'<textarea name="message"></textarea>'.
'<button>Send message</button></form>';
if ($f3->VERB=='POST')
echo 'Submitted message:<br>'.
nl2br($f3->get('POST.message'));
});
// Workaround here: $f3->mock is used instead of $f3->run
$path=$f3->get('GET.path');
if (#$path[0]!=='/')
$path='/';
$f3->mock($f3->VERB.' '.$path,$_POST);
It's still kinda possible, unfortunately you have to build most on your own.
Very basic example:
<?php
$f3 = require 'lib/base.php';
$f3->route('GET /', function() use($f3) {
switch($f3->get('view')) {
case 'user':
// do something
break;
case 'admin':
// do something
break;
}
});
The "/" route should work even without .htaccess.
Based on #xfra35's answer, I propose a solution that will allow you to have paths like this:
/index.php/foo/bar
Instead of:
/index.php?path=/foo/bar
But you still can use query variables (like /index.php/foo/bar?test=123) and get them using $_GET['test'] or $f3->get('GET.test'):
Just replace your $f3->run(); with:
$path=$_SERVER['PATH_INFO'];
if (#$path[0]!=='/')
$path='/';
$f3->mock($f3->VERB.' '.$path.'?'.$_SERVER['QUERY_STRING'],$_POST);
This question already has answers here:
Create route for root path, '/', with ServiceStack
(3 answers)
Closed 3 years ago.
I've got a Fallback DTO that looks like the following:
[FallbackRoute("/{Path*}")]
public class Fallback
{
public string Path { get; set; }
}
Now, in my Service I would like to redirect to an HTML5 compliant URL, and this is what I've tried:
public object Get(Fallback fallback)
{
return this.Redirect("/#!/" + fallback.Path);
}
It is working all fine and dandy, except for the fact that query parameters are not passed along with the path. Using Request.QueryString does not work as no matter what I do it is empty. Here's what my current (non-working) solution looks like:
public object Get(Fallback fallback)
{
StringBuilder sb = new StringBuilder("?");
foreach (KeyValuePair<string, string> item in Request.QueryString)
{
sb.Append(item.Key).Append("=").Append(item.Value).Append("&");
}
var s = "/#!/" + fallback.Path + sb.ToString();
return this.Redirect(s);
}
TL;DR: I want to pass on query strings along with fallback path.
EDIT: It turns out I had two problems; now going to mysite.com/url/that/does/not/exist?random=param correctly redirects the request to mysite.com/#!/url/that/does/not/exist?random=param& after I changed the above loop to:
foreach (string key in Request.QueryString)
{
sb.Append(key).Append("=").Append(Request.QueryString[key]).Append("&");
}
But the fallback is still not being called at root, meaning mysite.com/?random=param won't trigger anything.
In essence, what I want to do is to have ServiceStack look for query strings at root, e.g., mysite.com/?key=value, apply some logic and then fire off a redirect. The purpose of this is in order for crawler bots to be able to query the site with a _escaped_fragment_ parameter and then be presented with an HTML snapshot prepared by a server. This is in order for the bots to be able to index single-page applications (more on this).
I'm thinking perhaps the FallbackRoute function won't cover this and I need to resort to overriding the CatchAllHandler.
I managed to find a solution thanks to this answer.
First create an EndpointHostConfig object in your AppHost:
var config = new EndpointHostConfig
{
...
};
Then, add a RawHttpHandler:
config.RawHttpHandlers.Add(r =>
{
var crawl = r.QueryString["_escaped_fragment_"];
if (crawl != null)
{
HttpContext.Current.RewritePath("/location_of_snapshots/" + crawl);
}
return null;
});
Going to mysite.com/?_escaped_fragment_=home?key=value will fire off a redirection to mysite.com/location_of_snapshots/home?key=value, which should satisfy the AJAX crawling bots.
N.B. It's possible some logic needs to be applied to the redirection to ensure that there won't be double forward slashes. I have yet to test that.
How do you deal with the fact, that URLs are case sensitive in xPages even for parameters? For example URL:
my_page.xsp?folderid=785478 ... is not the same as ...
my_page.xsp?FOLDERID=785478
How to make, for example, a proper check that params contain some key e.g.
param.containsKey("folderid") which desnt work when there is 'FOLDERID' in URL.
I'd suggest defining a couple convenience #Functions:
var #HasParam = function(parameter) {
var result:boolean = false;
for (var eachParam : param.keySet()) {
if (eachParam.toLowerCase() == parameter.toLowerCase()) {
result = true;
break;
}
}
return result;
};
var #GetParam = function(parameter) {
var result = "";
if (#HasParam(parameter)) {
for (var eachParam : param.keySet()) {
if (eachParam.toLowerCase() == parameter.toLowerCase()) {
result = param.get(eachParam);
break;
}
}
}
return result;
};
Then you can safely query the parameters without caring about case. For bonus points, you could add requestScope caching so that you can skip looping through the keySet if you're examining a parameter that you've previously looked at during the same request.
you may use this function:
context.getUrlParameter('param_name')
then test if it's null or not.
make sure to decide for one,so either upper or lowercase
other than that i'd suggest something like
KeyValuePair<string,string> kvp = null;
foreach(KeyValuePair<string,string> p in param)
{
if(UPPERCASE(p.Key) == UPPERCASE("folderid"))
{
kvp = p;
break;
}
}
syntax isn't correct and idk the uppercase method in c# right now,but you get the point
The easiest answer is ofcourse the obvious. Be sure that the parameters you are using througout your application are always the same on every url you are generating and know what to expect. A good approach to accomplish this is to create a ssjs function which generates url's for you according to the objects you submit.
In this function you could check which object you are receiving and with the use of keywords and so forth generate the correct url. This way generating twice a url with the same input parameters should always generate the exact same url.
another option would be just to double check with a bit of code like this
var key = "yourkey";
if(param.contains(#uppercase(key)) || param.contains(#lowercase(key)){
// do stuff
}
But should not be necesarry if the url you are parsing is generated by your own application
Edit after post of topic starter
Another option would be to grap the url directly from from the facescontext and to convert it to a string first. When it is a string you can parse the parameters yourself.
You can combine server side substitution/redirection to get around the issue that David mentioned. So a substitution rule will redirect incoming patern like this:
http://myhost/mypage/param (/mypage/* => which converts to - /dbpath/mypage.xsp?*) - substitution is tricky so please handle with care.
Also I believe I read somewhere that context.getUrlParameter is not case sensitive - can someone please confirm this.
Hope this helps.