I'm trying to figure out what is the "proper" way to make HTTP requests programatically from web application code when you don't know if you are or are not running behind reverse proxy (e.g. HTTPD).
Web application runs on root "/" context on web server
Proxy runs with context "/proxy" that proxies this that web server
Accessing index.html from browser should be requested via /proxy/index.html.
But what if there is some code in the web application (e.g. myscript.js) that sends HTTP request programatically (e.g. xhr.open("???/resource").
And here comes the problem because the code sends this HTTP request to /resource instead of sending it to /proxy/resource.
In other words, the code of web application (that runs in the browser) does not know if there is any or there isn't a proxy. Keep in mind that application can run behind proxy but there may not be any proxy at all. I have in mind 3 solutions:
1) Web application resolves context (e.g. /proxy) automatically by parsing it from the current window.location.path and send xhr according to it
2) Enhance web application to require some additional configuration of proxy from user and it appends the context if it is set
3) Configure proxy somehow to also resend non-proxy like URLs to web server 1:1 (e.g. /proxy -> webserver/, / -> webserver/)
Which one is "the proper" one or there are any other options?
Backend web applications should not be aware if there is proxy or not above or before them. They should ideally live in their own context path, eg. /application/ and if they need to send redirects do so without using hostnames or url schemes in it, just URL-Path /application/*
Then ideally you can do easy reverse proxy directives according to your number 3 scenario:
ProxyPass /XXX/ http://backend/application/
ProxyPassReverse /XXX/ http://backend/application/
Related
I am trying to develop a node app and require a server that can only be used by the app internally.
I have tried instantiating a server without listening to the port, but can't do anything with it from that point forwards:
let http = require("http");
http.createServer(function (req, res) {
// custom code
})
This app is being built with NWJS and I need to intercept any outgoing requests (including file resources; CSS, JS, images, etc.) and modify the response, but I am not having any success with it except if I use a server for this purpose.
Problem is it becomes possible to open that server on any browser and I just want it to be used only inside the app or another way to intercept outgoing requests from the app so that the response body can be modified.
I have tried Keith's suggestion of using a service worker to intercept requests, but in my case I could not load a service worker from local environment into live environment (for example, run a local sw file in stackoverflow page), so that suggestion ended there.
Stdob's suggestion of using a proxy ended up being redundant and more troublesome than my original attempt.
In the end I went with my original attempt as follows:
Using chrome.webRequest.onBeforeRequest (Chrome API) and a local node server.
The server is created with an arbitrary port to reduce the risk of hitting an already used port.
The chrome API redirects all connections to the local server (ex. url: http://127.0.0.1:5050) and then the server will handle the requests as needed, returning the requested files modified or intact.
Last step, add a unique header with a unique value that only the app knows, so that no server access can be made from outside the app.
It is not the best solution, ideally I would prefer to have something like Firefox's webRequest.filterResponseData, but until Chrome implements that, this will have to do.
CONTEXT
In a Meteor app, I'm using a reverse-proxy to load the content of a third party site into an iframe. This allows me to inject CORS headers into the site, bypassing the cross-origin policy to allow me to make changes to the site. In particular, I'm using the http-proxy npm package: https://github.com/nodejitsu/node-http-proxy
PROBLEM
Since each user of my app should be able to load a different site into an iframe and make changes to it, I am wondering if it I need to:
Create a separate server each time I make a request for a new website, or
I can have a single proxy server, through which all website requests are passed
What would this look like - would I be loading proxyaddress/siteUrl into each user's iframe?
OK so I may be asking too much here and/or showing my naivety, but bear with me.
At present I have an html (with js) hosted at A, and node.js app hosted at B. The html/js fetches data from the node app via a XMLHttpRequest, and the node app at B dutifully generates the requested data and sends it to A.
I'm trying to reduce the number of http requests generally, and to streamline the performance generally, and wonder whether it's possible to host the html/js via the node app (via express.static()) at A so that when the html/js requests data from the node server, it's actually requesting data from the same server, and indeed all within the same app (since the node app is generating the data and the node app is also exposing the html/js to a static route).
So is there any way for the js in the html to access the node app functions more directly, i.e. rather than sending an http request to the same node app, just accesses the data-generating function within the node app directly, or at least without using an http request?
I have things set up in my node app so that the html/js can be hosted succesfully via express.static() -- so it's working OK to that extent -- but I just need to know whether it's possible to avoid an http request all the way round a big loop and back to the same node app!
The simple answer is, if A and B are far apart, yes, hosting them on the same server will help.
Serving them from the same application won't help as you'll still need to talk via HTTP.
The question of whether you can remove the HTTP calls from A to B is down to application design. You have a static web app and an API and you're basically thinking of scraping that and making it one application.
There are pros and cons to both but I'll be going down the road of personal opinion if I start listing them.
My vote, don't bother :)
When you serve html and js files by express.static() they are not running in server, but serve from server to browser. And so that js scripts are running from browser. Browser scripts to communicate with server, must use http/https requests or sockets. You can communicate browser scripts from server A with server B (but checkout CORS).
I have the following architecture for my app:
jQueryMobile web app --> Gets JSON from ---> REST API created in C#
I have placed the REST API Code in a virtual directory in IIS 6.
The Mobile site code is running in the root of the website... so the rough file structure is like this:
inetpub/
/index.html
myjavascript.js
/restapi/
web.config
Global.asax
bin/(bunch of Dlls...)
The Server is behind a network with the following sort of IP translation (not the real IPs...)
For example:
Web Server external IP: 121.131.141.50 (with URL http://mysite.com/)
Internal IP: 10.210.2.5
Subnet: 255.255.255.0
I have tried restricting access to the restapi folder by IP as I would like for it only to be accessible from the web server. I have tried the IIS approach and set Directory Security settings, and have also tried the approach of using a ServiceAuthorizationManager class to check Request IP in the Http Request.
Both approaches gave me the same result: There was no problem restricting and testing the actual service call through Fiddler to prove that a 401 would be thrown from any IP other than the web server IP: 10.210.2.5. I was also able to execute it from the webserver (which is the desired setup).
However, once the Mobile site javascript calls it, I get the 401 unauthorized. As the Javascript code is client side, the restapi assumes that the call is coming from the Client's IP address, which of course, is blocked.
Is there a neat way to check that the call comes from the IP where JavaScript is sitting?
Or Is there a better way to go about the whole thing?! :-/ Is there a way to make the web app specifically permitted to access the restapi virtual directory ?
Back to basics, your setup looks like this:
client <----> web server
HTTP
The web server hosts files which can be requested from outside by clients over the HTTP protocol. The web server is also where you filter incoming requests:
client <----> | web server
HTTP |
IP filter
If you say you want the REST service to be only accessible "on the same server", that means this:
client <----> web server
HTTP ^ |
| |
+----+
REST
But if the server is only talking to itself, you don't really need a full-blown REST interface to begin with. I guess what you actually mean is that the client, which downloads HTML and Javascript form the server, may request additional data from the server via REST.
client <----> web server
HTTP
<-------
HTML, JS files
-------->
AJAX
But as you see, the way it works is that the client downloads Javascript files from the server and executes that Javascript locally which then sends AJAX requests back to the server. The requests will always come from the client. They have to. It does not matter where the Javascript code that is making those requests originally came from. It could be a script from your server or it could be hand-typed by the user. An AJAX request is an HTTP request is an HTTP request like any other. Either you make your REST service accessible from outside or not, you cannot filter by the code that generated the request.
If you want to make the API non-public, require authentication so only registered users can access it. That doesn't make the API itself any less publicly accessible though.
I have a browser based app that needs to communicate with another service running on the client machine via a socket connection from the browser using JavaScript.
I need to post and parse XML back and forth on the socket.
I am unable to go down the flash path as the cross domain security is a barrier, ie the service running on the socket is not able to be modified to support Flash's crossdomain security.
What are my options for a pure JS based solution?
You've got two major problems here:
It's difficult in javascript to access non HTTP resources,
It's difficult in javascript to access resources not loaded from the same server.
There are exceptions to both of these, but the conjunction of exceptions available might not exactly match with what you need. Here are some possibilities:
Some sort of proxy on your own server that connects back to the machine with the XML service on behalf of your web app.
If you can control the client machine somewhat you can run a server on it that can embed the XML in a JSONP formatted http response, you can access by adding simple script tags, and send messages the other way by using a script tag to request a url with your data encoded into it.
If when you say 'socket' you're referring to an HTTP connection, then there are a number of options, one is to add a Access-Control-Allow-Origin header to the HTTP, then you can do gets and posts using normal XMLHttpRequests in recent browsers.
Javascript will not allow you to create a socket connection to the client. It would violate the same origin policy. If you could somehow save an applet/swf to the local machine you could serve it up as file:/// and it could communicate to localhost (maybe! not tested).
Maybe creating a proxy to go in front of this unmodifiable socket server could open up some options for you. You could then use something like flash, or you could just not use sockets.
Your options for socket based interaction is limited to plugins that support such live functionality. The options generally break down as follows Flash, Java and Silverlight. All of which aside from Java, if I recall correctly, will have similar policy requirements.
If you control your own server, you could create a socket service to proxy the request to the final destination. Or, depending on the interaction, you can use standard Ajax-style requests and have the socket interaction on your server-side code. If you don't need a persistent connection, having the socket interaction via the server is your best bet.