I'm in the process of splitting into two different projects an Ember.js app and its Express REST API counterpart. I assumed that things would be cleaner this way.
Until then, my Express app was both serving REST endpoints and all static files like index.html and app.js. But now, ember-cli is in charge of serving the static files and the Express app handles authentication + REST.
The last issue I'm having is that I now have two different ports: ember-cli uses http://localhost:4200 and express uses http://localhost:3333. When I get the session cookie from Express upon authentication, it's never being sent on subsequent request because of same origin policy (see: How do I send an AJAX request on a different port with jQuery?).
Now if I understand correctly I have two solutions:
Setup Express to support JSONP and make sure Ember uses it too
Install a local Nginx or Apache and setup a proxy pass
The first solution is not ok because after deployment both apps will use the same domain/port. The second solution would probably work but it seems a bit ridiculous to ask developers to install a local web server to simply run an app.
I'm sure many of you have encountered that issue before. What would you suggest to make development easy?
Thanks!
Hmm. Seems like I found another solution:
Following instructions found there: http://discuss.emberjs.com/t/ember-data-and-cors/3690/2
export default DS.RESTAdapter.extend({
host: 'http://localhost:3333',
namespace: 'api',
ajax: function(url, method, hash) {
hash = hash || {}; // hash may be undefined
hash.crossDomain = true;
hash.xhrFields = { withCredentials: true };
return this._super(url, method, hash);
})
});
You will also need to add the following headers in the Express app:
// Add support for cross-origin resource sharing (localhost only)
app.all('*', function(req, res, next) {
if (app.get('env') === 'development') {
res.header('Access-Control-Allow-Origin', 'http://localhost:4200');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
}
next();
});
That's it! Last step is to make sure that Ember uses CORS only in the dev environment.
UPDATE
Ember-cli now has an integrated proxy feature that makes all the above obsolete.
From documentation: "Use --proxy flag to proxy all ajax requests to the given address. For example ember server --proxy http://127.0.0.1:8080 will proxy all your apps XHR to your server running at port 8080."
Related
I've got a Next.js application that uses AWS Cognito userpools for authentication. I have a custom UI and am using the aws-amplify package directly invoking signIn/signOut/etc... in my code. (I previously used the AWS Hosted UI and had the same problem set out below - I hoped switching and digging into the actual APIs who reveal my problem but it hasn't)
Everything in development (running on localhost) is working correctly - I'm able to login and get access to my current session both in a page's render function using
import { Auth } from 'aws-amplify';
...
export default const MyPage = (props) => {
useEffect(async () => {
const session = await Auth.currentSession();
...
}
...
}
and during SSR
import { withSSRContext } from 'aws-amplify';
...
export async function getServerSideProps(context) {
...
const SSR = withSSRContext(context);
const session = await SSR.Auth.currentSession();
...
}
However, when I deploy to AWS Amplify where I run my staging environment, the call to get the current session during SSR fails. This results in the page rendering as if the user is not logged in then switching when the client is able to determine that the user is in fact logged in.
Current Hypothesis - missing cookies(??):
I've checked that during the login process that the AWS cookies are being set correctly in the browser. I've also checked and devtools tells me the cookies are correctly being sent to the server with the request.
However, if I log out context.req.headers inside getServerSideProps in my staging environment, the cookie header is missing (whereas in my dev environment it appears correctly). If this is true, this would explain what I'm seeing as getServerSideProps isn't seeing my auth tokens, etc... but I can't see why the cookie headers would be stripped?
Has anyone seen anything like this before? Is this even possible? If so, why would this happen? I assume I'm missing something, e.g. config related, but I feel like I've followed the docs pretty closely - my current conf looks like this
Amplify.configure({
Auth: {...}
ssr: true
});
Next.js version is 11.1.2 (latest)
Any help very much appreciated!
You have to use Next#11.0.0 to use getServerSideProps, withSSRContext and Auth module in production.
I had same issue.
My solution was that disconnect a branch has an authentication problem once and reconnect the branch.
What are your build settings? I guess you are using next build && next export in which case this getServerSideProps shall not work. See https://nextjs.org/docs/advanced-features/static-html-export#unsupported-features
To use SSR with AWS amplify see https://docs.aws.amazon.com/amplify/latest/userguide/server-side-rendering-amplify.html#redeploy-ssg-to-ssr or consider deploying on a node server that is actually a server that you can start with next start like AWS EC2 or deploy on Vercel.
Otherwise if you use next export have to make do with client side data fetch only with client side updates only and cannot use dynamic server side features of nextjs.
One reason for context.req.headers not having any cookie in it is because CloudFront distribution is not forwarding any cookies.
This “CloudFront Behaviour” can be changed in two ways:
Forward all cookies, OR
Forward specified cookies (i.e. array of cookie names)
To change the behaviour, navigate to CloudFront on AWS console > Distributions > your_distribution > Behaviors Tab.
Then Edit existing or Create new behaviour > Change cookies settings (for example set it to "All")
I run Django and Vue together and the combination works fairly well. Django runs on http 8000 and webpack dev server chugs along on port 3000, JS or Vue changes get compiled automatically and I just have to reload the page (this is not an SPA app).
Django-webpack loader is used to serve the bundles via tags like:
<script type="text/javascript" src="http://localhost:3000/static_src/bundles/pssystem/data.js" ></script>
I do not use Vue-CLI and have no intention to move from a Django to a Node frontend.
Life is good, everything else works fine.
The only annoying bit is repeat requests like this:
http://localhost:8000/sockjs-node/info?t=1607750560606
This is what the devtools show for host:port requests. App is on 8000 w. Django, bundles 3000 with devServer, socksjs needs to be on 3000 too.
Now, Django doesn't find that resource so its log clutters up with 404. I actually coded a 410 instead, but, no, Vue is just going to ping and ping and ping that 410.
#urls.py
url("^sockjs-node/info", views.nodeinfo),
#views.py
def nodeinfo(request):
return HttpResponseGone()
Now, I have tried to look for this. The answers on the Vue forum are multiple and most involve changing to vue.config.js, located next to package.json.
UPDATE: since I am NOT using Vue-cli, it seems the settings need to go in webpack.config.js instead.
After trying 2 or 3 of the suggestions, most of which don't seem to make much sense (a localhost question ends up with a "fix" consisting of a devserver entry pointing to 0.0.0.0 for example), none of them work.
devServer configs which have NOT helped:
{
hot: false,
port: 3000
};
{public: 'localhost:3000'}
{sockPort: 3000}
{sockPort: 3000,sockHost: 'localhost'}
{inline: false}
None of the threads I have seen seem to hold very authoritative answers. Or, more likely, I can't find the correct answer in all the noise that is being posted.
(I did see one suggesting to change the webpack command instead by adding --no-inline flag, but haven't tried it out).
I won't be running node in production, will only run webpack bundling to staticfiles. I don't care about https here. I also don't care to get sockjs working by reconfiguring stuff - things work perfectly well without whatever is missing, so turning it off can't hurt.
I ONLY want those requests to STOP going out from the client code. Entirely. How do I do that?
(P.S. If you want to answer, please indicate in what way your proposed contents of vue.config.js address the issue - I have just seen too many this fixed it with not the slightest bit of info on how the configuration contents serve to turn this off. That means whoever uses that solution doesn't understand it and uses copy-and-pray programming).
Versions:
vue#2.6.11
webpack-dev-server#3.11.0
npm --version 6.14.6
node --version v10.15.0
Last but not least, these are my webpack goals:
Watch and recompilation on the server whenever I change the JS/Vue files, bundles on 3000 are refreshed.
The main server functionality stays with Django serving up html via server-side templates, on a different port than node's devServer.
No need for hot module reload on client. It is perfectly OK for me to keep using the stale bundles until I refresh the page. This is not, and could not be, an SPA or Node frontend app.
(OP's edit: this answer got the bounty, because it told me Vue was less relevant here than Webpack and because my investigation of Webpack's relevant configuration option then showed nothing that manage to turn off these requests. The takeaway I have for now is that this can't be done - as far I understand, if Django is serving at :8000 then Webpack HMR's implicitly expects to be able to poll at the same host:port, without an option to re-route or turn it off. So, the tentative answer is more of a no, can't be done).
Since you're not using the Vue CLI, you'd need a webpack.config.js, rather than vue.config.js. Assuming your devServer is running at localhost:3000, (I'm not certain about your non-standard setup) you can try this in webpack.config.js in your project root:
module.exports = {
devServer: {
host: 'localhost',
port: 3000
}
};
If this doesn't work, I recommend recreating your project with Vue CLI and using a separate repo/package.json for your backend in a server folder.
To add to the accepted answer: Additional requests to http://localhost:8000/sockjs-node/info?t=123 with the wrong port may be caused by a webpack plugin. In my case the culprit was ReactRefreshWebpackPlugin. The solution was to tell that plugin which port webpack dev server was on:
// …in webpack.config.js…
plugins: [
isDevelopment && new ReactRefreshWebpackPlugin({
overlay: {
sockPort: 3000, // <-- Tell plugin which port WDS is running at
},
}),
].filter(Boolean),
devServer: {
hot: true,
port: 3000, // I used port 3000 here because of the setup in OP's question
}
Docs: https://github.com/pmmmwh/react-refresh-webpack-plugin
We've built a framework around Nuxt to get it to work with WordPress really well. We have been pulling our hair out trying to get post previewing working.
A common setup will be a WordPress install running on a domain like http://api.example.com and then to have Nuxt running on http://www.example.com. There is a WordPress plugin called WP-Graph-QL that creates a GraphQL endpoint like http://api.example.com/graphql, and we wrote a CORS plugin to set the correct CORS headers to work with whatever the frontend origin may be. This is that plugin if you are curious https://github.com/funkhaus/wp-graphql-cors
Our Nuxt Apollo setup is this:
export default function() {
return {
httpEndpoint: process.env.DEFAULT_ENDPOINT,
getAuth: () => process.env.BASIC_API_TOKEN || "",
httpLinkOptions: {
credentials: "include"
}
}
}
FYI sometimes the API will be hidden behind a Basic Auth UN/PW (like when on a staging site for example), that is what the getAuth function is doing.
This all seems to work client side, but it fails on SSR for some reason. It seems the cookies don't get sent in the SSR request, but they do in the client side request. Am I missing something super obvious here?
NOTE: I asked this question here 8 days, but am trying here for more attention
I'm using the ember-cli-simple-auth with ember-cli and everything it working great, until I try and set a new host on DS.RESTAdapter application wide.
As soon as I set
// adapters/application.js
exports default DS.RESTAdapter.extend({
host: 'https://api.example.com'
});
or even using reopen() it clears all the headers set by ember-simple-auth.
Am I not setting this up right in ember-cli?
If you're using a different domain for the REST API you need to configure that for OAuth 2.0 authenticator (assuming you're using that) and also make sure you have CORS enabled on the server side. You can find a tutorial here: http://log.simplabs.com/post/90339547725/using-ember-simple-auth-with-ember-cli.
please can you advise on the following:
I have a web application written in emberjs with Rails as back-end. And now I'm going to port this application with phonegap to iOS, and the thing that I'm struggling is how to set my API endpoint that will be working in iPhone?
As I understand EmberJs when used on the web via browser, uses your current location to issue API requests, but this approach doesn't working when using the application as iOS app.
I'm really looking for some elegant solution to simply replace the host name or something?
Thanks for help!
UPDATE:
This one works for changing the API URL
DS.RESTAdapter.reopen({
url: 'http://somedomain.com'
});
But now, there is access-controll issue:
Origin http://somedomain.com is not allowed by Access-Control-Allow-Origin.
Since you haven't posted any code on how your adapter is configured, this is the right way to set a custom url for your adapter:
DS.RESTAdapter.reopen({
url: 'https://somedomain.com/api'
});
Then if you have a model e.g. App.User, the requests for the list of App.User would now go to https://somedomain.com/api/user/ and for a specific user id to https://somedomain.com/api/user/123 respectively.
Update
When testing from the browser you have to start the browser (assuming chrome) with the flag --disable-web-security to make cross origin work. But in real live you have to configure your server to set the response HTTP HEADERS using:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, ...
So in the case of rails you could do something like this to configure your controllers serverside to accept cross origin requests and set the headers accordingly:
...
after_filter :cors_set_access_control_headers
def cors_set_access_control_headers
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT' # etc. etc.
headers['Access-Control-Max-Age'] = "1728000"
end
...
For more extensive examples on how to configure CORS for rails you could search for "CORS for JSON and Rails" for example.
Hope it helps