Is there an equivalent module for Node.js that does what Apache's mod_rewrite does? or is there a standard language construct that provides equivalent functionality?
I'm just getting started with Node and looking to convert my server to this platform.
If you are looking for a good modrewrite library. You might want to look at connect-modrewrite
If you have a HTTP server running with NodeJS you have 2 objects, request and response. The request contains the requested url. Using a require('url') you can parse this requested url and for example get the pathname that's requested.
What you then do with it, is up to your own code obviously. So based on the default example on www.nodejs.org you'd end up with something like this:
var http = require('http');
http.createServer(function (req, res) {
var requestedURL = require('url').parse( req.url );
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write( "You requested " + requestedURL.pathname + "\n" );
res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
Which you can test with http://127.0.0.1:1337/foo/bar. Where you can use requestedURL.pathname to determine what you'd want to do, ideally you'd create your own - or use a 3rd party - routing library. They are available, ExpressJS is a pretty famous NodeJS framework which might help take care of a lot of things for you, but I have no experience with it myself.
More information:
Now dead: [http://www.robsearles.com/2010/05/31/nodejs-tutorial-part-2-routing/]
http://expressjs.com/
As suggested by the previous answers you need to write it yourself; the two previous answers were both more orientated towards handling different paths specially.
You might find my node reverse proxy helpful, as it has a lot of code for handling rewrite rules. This is different than the previous answers because it allows you to match on a rule such as "/people/([a-z]*)" and redirect to "/cgi-bin/index.cgi?user=$1" which is very similar to mod_rewrite.
If you're looking for an equivalent (although not technically, because routers don't actually "rewrite" anything), there are a number of routers out there. Most notably the Connect router (upon which Express is built): https://github.com/senchalabs/connect
It will look something like this:
app.get('/', function(req, res) {
res.end('hello, here is the home page.');
});
It might be better to mess around with the lower-level http interface first though, to get a good feel for it.
There is a rewrite module. And when used with another proxy module in the middleware, they work together as a Reverse Proxy.
I use them while developing Single Page Applications in my local box (so I dont have to configure apache/nginx locally)
This in order to avoid CORS and send all pages (except js/css/images) to index.html for the SPA to work.
var connect = require('connect');
var modRewrite = require('connect-modrewrite');
var proxy = require('proxy-middleware');
var url = require('url');
var app = connect()
.use(modRewrite([
"^\/api\/(.*) /send-to-api/api/$1 [L]",
"^(.*)\/css\/(.*) /send-to-ui/css/$2 [L]",
"^(.*)\/js\/(.*) /send-to-ui/js/$2 [L]",
"^(.*)\/images\/(.*) /send-to-ui/images/$2 [L]",
"^(.*)\/fonts\/(.*) /send-to-ui/fonts/$2 [L]",
"^(.*) /send-to-ui/index.html [L]"
]))
.use('/send-to-api', proxy(url.parse('http://api.server.dev/'))) // Don't forget the last backslash
.use('/send-to-ui', proxy(url.parse('http://ui.server.dev/' ))) // Don't forget the last backslash
.listen(9000)
Check that I use [L] flag because I want it to rewrite and skip the rest of the rules.
In this case, only the /api urls get proxied to api.server.dev, the rest goes to ui.server.dev.
The url prefixes /send-to-api and /send-to-ui are temporary and I use them to differentiate what will go where, it is removed by the connect before sent to their respective servers.
And yes, in case of redirects, proxy-middleware will change the Location header to be localhost:9000
Related
My NET Core application exposes a Webmethod.
This method needs to accept a URL as parameter for further processing.
e.g.
mysite.com/webmethod/url=https://www.google.com
It would never go through.
Instead, it shows Page Not Found.
It seems this webmethod will never be routed to my controller if there is a forward slash in the URL.
However, after getting rid of forward slash, it works very well.
mysite.com/webmethod/url=https:www.google.com
Could someone tell me how to deal with forward slash?
Thank you.
You can use UrlEncode and UrlDecode.
var queryString = UrlEncode("https://google.com"); // https%3A%2F%2Fgoogle.com
var decodedString = UrlDecoce(queryString); // https://google.com
our site makes 200+ requests. about 100 are our own urls (images, css, js, fonts etc). the other 100 are google analytics, newrelic, tealium, and lots of dross.
i want to match all, and only, requests to our site, which is www.mysite.com.
In "URLS Patterns to Include" I tried:
.*mysite.com.*
But this also includes many of the marketing requests which include the site name in the url parameters.
Next I tried this:
https:\/\/mysite.com.*
https:\/\/www.mysite.com.*
but get no results back.
what is the proper way to include only, and all, resources loaded from your own domain?
I think this could be the way:
^www.mysite.com.*
It seems to return the right number of requests (when I clear cache before recording of course)
Is this the best solution?
If you look at ProxyControl.generateMatchUrl() function source code you will see the following:
private String generateMatchUrl(HTTPSamplerBase sampler) {
StringBuilder buf = new StringBuilder(sampler.getDomain());
buf.append(':'); // $NON-NLS-1$
buf.append(sampler.getPort());
buf.append(sampler.getPath());
if (sampler.getQueryString().length() > 0) {
buf.append('?'); // $NON-NLS-1$
buf.append(sampler.getQueryString());
}
return buf.toString();
}
Pay attention to this sampler.getDomain() bit which returns DNS hostname or IP address of the URL so if you add protocol there (http or https) the function will not match anything.
So you will have to provide patterns without protocol section like in the "Suggested Excludes"
If you have to include the protocol - I think you will need to re-consider your approach to recording and switch to i.e. JMeter Chrome Extension which provides possibility to filter the requests including the protocol:
Moreover you won't have to worry about proxies, certificates, etc.
I would like to apply a reverse proxy on top of S3 to make content serving decisions based on the incoming request.
The S3 bucket is set to website mode and hosted publically.
I'll obviously have more logic to determine where I am getting the files from, but hopefully this will illustrate my desire.
This is using JavaScript, happy to use Go as well.
The following code does not work, but I'm not sure how best to get it working. Can I just send an arrayBuffer through?
module.exports.handler = async (event, context) => {
const data = await fetch(S3WebsiteURL + event.path)
const buffer = await data.arrayBuffer()
return {
headers: data.headers,
body: buffer,
statusCode: 200
}
}
I would use https://www.npmjs.com/package/request-promise
var rp = require('request-promise');
const htmlString = await rp(S3WebsiteURL + event.path);
return {
body: htmlString,
statusCode: 200
}
Try without headers and if it works, add header support.
I've found it difficult to use Lambda to proxy data - using API gateway, at least, it expects binary data in base-64 format at various points depending on how you set it up. They've improved things since I tried to do it that way last, so hopefully someone else can answer based on more recent experience.
If your content serving decisions are limited to access control (you don't need to transform the data you're serving), then you can use your lambda as a URL provider instead of a content provider - switch public sharing of the S3 bucket off, access the items using the S3 API, and have your lambda call S3.getSignedUrl() to get a link to the actual content. This means that only the callers of the lambda will have a valid URL to the content you want to protect, and depending on your application you can set the timeout on the pre-signed URL to be short enough you don't have to worry about it being shared.
The advantage here is that since the content itself doesn't get proxied through the lambda, your lambda runtime and memory costs can be lower and performance should be better.
I need to do a URL rewrite in a ServletFilter so that "foo.domain.com" gets rewritten to "foo.domain.com/foo". I'm using Jetty, which has a handy way of modifying requests: just cast the request to a Jetty Request object and you get a bunch of setters which allow you to modify it. Here's my code (which doesn't work):
String subdom = Util.getSubDomain(req);
org.eclipse.jetty.server.Request jettyReq = (Request) req;
String oldUri = jettyReq.getRequestURI();
String newUri = "/" + subdom + oldUri;
jettyReq.setRequestURI(newUri);
My purpose is to serve files out of the /foo directory, which lives at /webapps/root/foo.
I'm guessing that I also need to call things like setContextPath(), setPathInfo(), setURI(), setServletPath(), and who knows what else.
What's the magic combination that will make it look like the original request was for /foo?
Edit: to clarify, the reason I say the code doesn't work is that files are still being served out of /webapps/root, not /webapps/root/foo.
Just use the rewrite handler, we have support for what you're trying to do:
http://wiki.eclipse.org/Jetty/Feature/Rewrite_Handler
Answering my own question: I was missing
jettyReq.setServletPath(newUri);
Add that and everything works.
Having some annoying issues making AJAX calls simply because almost every browser these days is making an OPTIONS call to the server before the actual AJAX call.
Since I am using Play! 2.0, is there any easy way to make a wildcard response to any route using the OPTIONS method?
For instance, in my routes do something like:
OPTIONS /* controllers.Options.responseDef
Yes I am aware that the new Play! doesn't have a wildcard built-in, but there needs to be a solution for this since all browsers are increasingly calling OPTIONS before AJAX calls.
Not quite a wildcard, but you can use a route which spans several slash-segments:
OPTIONS /*wholepath controllers.Options.responseDef(wholepath)
OPTIONS / controllers.Options.responseDef
It should match all the requests:
OPTIONS /a
OPTIONS /a/b
OPTIONS /a/b/c
Note: that's from the top of my head, so maybe you'll need to polish it. I can't check it now by myself.
Check the section Dynamic parts spanning several / of the manual.
A very clean way to have a single controller endpoint match all OPTIONS requests is to override the onRouteRequest method of Play's Global object. The following version of onRouteRequest will route all requests to a single endpoint named OptionsController.options.
import play.api.mvc._
...
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
request.method match {
case "OPTIONS" => Some(OptionsController.options)
case _ => super.onRouteRequest(request)
}
}