I'm currently working on an Angular 2 web application which communicates with an API. In the application the user is able to choose a payment option and the API will return the url to the payment service.
The problem is that the payment service uses POST to go to the confirmation page which WebPack does not accept (for some reason it only allows GET requests) and we get the following error:
Cannot POST /selection/payment-method
Does anybody know how we could configure that WebPack allows POST requests also? I've contacted the payment provider but it is not possible to do a GET request instead of POST.
Thanks
Based on #Sven's answer, modification to the setup so that it works for POST all throughout
Add dependencies on body-parser, sync-request and add require dependencies on both in your webpack.config.js
var bodyParser = require('body-parser');
var request = require('sync-request');
In devServer part of webpack.config.js
devServer: {
setup: function(app) {
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post(/^\/(URL1|URL2|URL3)\//, function(req, res) {
var serviceCallResponse = request('POST', 'your app server url here' + req.originalUrl, {
json:req.body
});
res.send(serviceCallResponse.getBody('utf8'));
});
},
proxy: {
'*/other URLs proxy/*': 'your app server url here'
}
}
Change URL1/2 to the URLs you want to proxy and you place your app servers address.
This will work for all sorts of POST request proxy (working on json payload)
A hackish way to at least not get 404 errors is to proxy requests to /selection/payment-method and send back an empty response (or whatever content you want, I think that res is an instance of Express's Response class) for those, by adding the following to webpack.config.js:
devServer: {
proxy: {
'/selection/payment-method': {
bypass : (req, res) => res.end()
}
}
}
Documentation here.
Thanks to #robertklep who send me the link to the proxy documentation we found a way to deal with it. What we needed to do was instead of handling the POST request we needed to transform it someway into a GET. After reading some more of the documentation we came across the setup: property for your webpack-dev-server configuration.
With the setup: property you get the expressjs object and you are able to catch urls before it hits the route that says Cannot POST /url/to/page.
We ended up with this:
devServer: {
setup: function(app) {
app.post('/selection/payment-method', function(req, res) {
res.redirect('/selection/payment-method');
});
},
}
This way we got a GET request instead of POST and our application does an API request to check if the payment succeeded or not.
This is only used in development!
The Webpack-dev-server is only intended as your front-end server only, eg. to serve your static assets. Therefore only GET requests are supported.
If you would want to use a proxy or backend server, then you should implement this. You can use Express for this.
See how you can setup basic routing.
Related
I am implementing http proxy middleware in to my react app. I want to proxing qa or dev backend services urls from my local .
Example of my dev login url below
https://cors-anywhere.herokuapp.com/https://dev.sju.uk/auth/login
my setupProxy.js
module.exports = function (app) {
app.use('/auth/login' ,createProxyMiddleware({
target: 'https://cors-anywhere.herokuapp.com/https://dev.sju.uk/auth/login',
changeOrigin: true,
})
);
};
I started my app and click the login button and the request got failed with 404 not found error . Not sure why my target is not replacing with my actual http://localhost:9009/auth/login uri to https://cors-anywhere.herokuapp.com/https://dev.sju.uk/auth/login.
Also am not getting proxy created message in my console when we do npm start as well. I am using webpack dev server not react-scripts . If any changes required on webpack side or am i missing anything badly please let me know. I tried small poc it got worked but that is simple without herokuapp things.
It took me some time to understand how the http-proxy-middleware works.
Look at the following diagram from the http-proxy-middleware Docs
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
For simple configurations, any request that your front-end does calling an API get observed by a matching pattern on the path section of the above diagram and overwritten with your target configuration, to be exposed in the header of the request as a different URL. This also help you in the development phase locally to avoid the CORS blocking mechanism of the browsers.
Example:
Let's imagine we need to call from our front-end exposed at http://localhost:3000 to an endpoint located at https://localhost:7005/api/WeatherForecast
This type of calls will be blocked in all browsers by CORS.
So, with the following config, you will be able to bypass the cors problem.
const { createProxyMiddleware } = require('http-proxy-middleware');
const context = [
"/api",
];
module.exports = function (app) {
const webApiProxy = createProxyMiddleware(context[0], {
target: 'https://localhost:7005',
secure: false,
changeOrigin: true,
headers: {
Connection: 'Keep-Alive'
},
logLevel: 'debug'
});
app.use(webApiProxy);
};
With this, any request made from http://localhost:3000 will be intercepted by the proxy-middleware and if it finds a /api in some part of the path will be changed to https://localhost:7005/api and also concatenate the rest of your original path following the /api.
So finally, your front-end will be asking things from http://localhost:3000 but all the request will arrive to https://localhost:7005 as if they were request by https://localhost:7005 and this will fix the Cors problem coz your requesting and responding from the same origin.
I Guess your can fix your problem by writting your config this way:
module.exports = function (app) {
app.use('/auth/login' ,createProxyMiddleware({
target: 'https://dev.sju.uk/auth/login',
changeOrigin: true,
headers: {
Connection: 'Keep-Alive'
},
})
);
};
Bare in mind, this libray not only can help you with the CORS problem but also to perform hundred of things for any request/response like change arguments from the body, add things to the body, add headers, perform operations before the request aka logging what's requested, perform operations on the response aka logging again what has returned, etc, etc.
Hope this will help to resolve your issue!
GET http://localhost:3000/api/fetch?search=12312321 404 (Not Found)
cors issue in Reactjs and node js
i use the proxy method in Reactjs but can't get rid from it please help me
proxy
"proxy":"http://localhost:5000/"
tried both
"proxy":"http://localhost:5000"
express
RegisterRoute.route('/fetch/:id').get( ( req , res) =>
{
console.log("called by someone ",req.params.id);
res.send("okey will");
});
Reactjs function which will call the backend api
FetchNotification(){
axios({
'method':'GET',
'url':'api/fetch',
'headers': {
'content-type':'application/octet-stream',
'x-rapidapi-host':'example.com',
'x-rapidapi-key': process.env.RAPIDAPI_KEY
}
,
'params': {
'id':'12312321'
},
})
}
when i simply call axios.get it perfectly work but when i give params to it it gives the error xhr:178 404 not found
a simple server which also returns the same result
const express = require('express');
const cors= require('cors');
const app= express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use('*',cors());
app.get('/fetch/:id',(req , res) => {
console.log("calling",req.params.id);
});
app.listen(5000);
I can see that you're using Nodejs as server side. So, you can try changing following line
app.use('*',cors());
to
app.use(cors());
If this doesn't solve the issue, you can try adding a google chrome extension for CORS (Most probably). In this way, you'll not need any proxies being set for running servers.
Also, you need to do a small change in URL, instead of calling
'url':'api/fetch'
you need to provide an id in your call, because the backend api is accepting a parameter
'url':'api/fetch/some_id'
I feel there are multiple issues. I'll try to address them one by one.
Firstly, if you are proxying your requests correctly (which I think you are as per your package.json), then you'd not require the cors package. So you can get rid of that package.
Read more about why you shouldn't let all incoming request bypass the CORS check from security point of view -> Is it safe to enable CORS to * for a public and readonly webservice?
Now secondly, the url which you've specified on the frontend is 'url':'api/fetch', which means browser will make a call to http://localhost:3000/api/fetch?search=12312321 which it correctly did as seen in your error statement for 404.
Specifying the proxy as "proxy":"http://localhost:5000" in package.json means that now you are making requests to http://localhost:5000 instead of http://localhost:3000, but the browser would still think its http://localhost:3000. That's the whole purpose of proxying and how you kinda fool browser to do CORS without throwing any error.
But because on your server, you are listening to app.get('/fetch/:id',(req , res) instead of app.get('api/fetch/:id',(req , res), it doesn't matches with this URL as you have not explicitly handled requests starting with /api in some separate router module either.
So you should either update the url in the axios call to url':'/fetch while the proxy value in package.json is "proxy":"http://localhost:5000" or url':'fetch and "proxy":"http://localhost:5000/" respectively. Notice how i've used the /
OR
You can update the URL on the express end to app.get('api/fetch/:id',(req , res)
Lastly, whenever you receive a request, you need to return some value(string or JSON or even status code) as result.
In your case, you've simply console.log("calling",req.params.id); and didn't send back any response to the UI.
So even if your 404 would resolve after fixing the URL, you'd bump into request timeout error (408) as your UI will keep waiting for a response from the server while you didn't send any.
So you should do something like this maybe:
app.get('api/fetch/:id',(req , res) => {
console.log("calling",req.params.id);
res.send("It worked");
});
Notice how there's a response being sent back -> https://expressjs.com/en/starter/hello-world.html
If you don't want to send back a response, then you can simply return status like 200, 504 etc.
if you apply below code in backend/server i thing it will debug.
app.get('api/fetch/:id',(req , res) => {
console.log("calling",req.params.id);
res.send("It worked");
});
I'm building a Shopify App with React & Express, deployed via Heroku, which I'm trying to embed into my storefront using an Application Proxy.
When I finally load the proxied URL on my store - I get a blank screen and a bunch of 404's in the console for my .css and .js chunk files. The request was sent, authenticated, and my API's response is (200) - it just won't render anything.
Finally, after much research, I realized that Shopify has changed the path to these CSS and JS files to be my-store.myshopify.com/hash.chunk.js etc. instead of the reference to my Heroku server.
It appears this problem has been encountered before in this thread: Shopify app - how to include assets using an app-proxy with ruby on rails However, I can't seem to find a node/react/heroku equivalent to the Ruby solution presented here.
Any guidance or help would be greatly appreciated!
I begin by serving my React App through express with:
app.use(express.static(path.join(__dirname, 'client/build')));
and then when my proxy URL is hit I send back the index file within the client/build folder:
router.get('/proxy', (req, res) => {
res.set('Content-Type', 'application/liquid').sendFile(path.join(__dirname, '../client/build/index.html'));
});
I've managed to find a working solution to my problem after much trial and error.
The homepage in package.json is important. I had it set to just my Heroku address when it should actually be set to herokuaddress.com/YOURPROXYROUTE (i.e. /app/my-app)
Some additional middleware is required as well - for those interested I have the following routes set up to field requests from Shopify's app proxy.
This is set up above any of my route imports in server.js:
app.use(express.static(path.join(__dirname, 'client/build')));
and these routes are imported below that from a /shopify-routes.js file:
router.get('/proxy', (req, res) => {
res.set('Content-Type', 'application/liquid').sendFile(path.join(__dirname, '../client/build/index.html'));
});
router.get('/proxy/static/css/:file', (req, res) => {
res.set('Content-Type', 'text/css').sendFile(path.join(__dirname, `../client/build/static/css/${req.params.file}`));
});
router.get('/proxy/static/js/:file', (req, res) => {
res.set('Content-Type', 'text/javascript').sendFile(path.join(__dirname, `../client/build/static/js/${req.params.file}`));
});
Though this may be a bit heavy-handed, it has solved the problem and the app is loading within the Shopify storefront now.
I have a simple React app, created with create-react-app, that I'd like to deploy to Heroku (or somewhere easy) and password-protect. The protection can be really simple—just a single password is fine.
I started looking into HTTP basic auth but didn't find an easy answer. The closest I found was in this post, but (a) I don't love the idea of having to eject my app, and (b) I couldn't get it working. I was hoping I could find a Heroku plugin, but no luck there either.
It wouldn't be too hard to write a component that wraps my app and requests a password before showing it. The problem is that it executes client-side. I want to store the correct password server-side (or a hash thereof), and have the app send password attempts up to the server.
Since create-react-app operates on top of Node, I'm hoping there's an easy way to tell it to execute and store certain things on the server, but maybe I'm wrong. Any suggestions?
This create-react-app buildpack seems to support http basic auth:
https://github.com/substantial/create-react-app-buildpack
https://elements.heroku.com/buildpacks/substantial/heroku-buildpack-static
I am assuming your intentions are wanting to protect the config vars in heroku so other people cannot access you database with your credentials.
The way I password protected my deployment to heroku, is to make a keys_prod.js file containing the Heroku config vars of my mLab database in my backend using express and mongoDB:
keys_prod.js file:
module.exports = {
mongoURI: process.env.MONGO_URI,
secretOrKey: process.env.SECRET_OR_KEY
};
keys.js file:
if (process.env.NODE_ENV === 'production') {
module.exports = require('./keys_prod');
} else {
module.exports = require('./keys_dev');
}
in my server.js file I added:
// DB Config
const db = require('./config/keys').mongoURI;
// Server static assets if in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
This allows you to request the config vars you filled in heroku without including it in your repo.
If you use Node in backend you can use Passport Basic Auth
app.get('*', passport.authenticate('basic', { session: false }), (req, res) => {
res.sendFile(path.join(`${__dirname}/../build/index.html`))
})
Every time you access the page in browser, a popup will appear, asking you username and password.
I'm developing a new Angular client which should communicate with my Node/Express server. I'm currently trying to develop the first step aka the login. This should be an http json post. It turns out that every single time I execute that post from the client to the server, the Node/Express server doesn't find the route for my path.
On the console log of the server, for my post json request I find following stacktrace:
OPTIONS /api/auth/facebook/mobile 404 274.092 ms - 1980
Node/Express side:
My route
app.post('/api/auth/facebook/mobile', authenticationHandler.handleFacebookMobileLoginRequest);
Body parser for json is defined:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
On the Angular client side, I do:
http({
method: 'POST',
url: 'http://192.168.1.101:3000/api/auth/facebook/mobile',
headers: { 'Content-Type': 'application/json; charset=UTF-8;' },
data: {fbToken: authResponse.accessToken}
})
.then(function (response) {
...
Fun facts:
Same route works fine when I call it from a Java app or and Android native app, like
final JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, SERVER_URL + "/api/auth/facebook/mobile", params, jsonRequestListener, errorListener);
On my Angular client, when I change data with params then it works, the route is found...but I mean that doesn't make any sense. Moreover, I've got then a problem on the Angular client side, the answer isn't processed respectively the answer never land in the .then(... function. Which again works well in other clients.
Anyone got an idea, a clue or should I call Dr. Strange?
Possible browser preflighted request CORS issue?
Try using CORS module in Node.js server:
var cors = require('cors')
app.use(cors());