I have a simple Node.js server up and running. This is the code:
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
res.writeHead(200, {
'content-type': 'text/plain'
});
res.write('Hello World!');
res.end();
})
server.listen(8090);
server.once('listening', function() {
console.log('Hello World server listening on port %d', 8090);
});
I can call this server using curl from the command line:
$curl localhost:8090
However, when I try to call it from a Vue application, I get an error. I have a Vue application running on localhost:8080, and I want to call my localhost:8090 server. My main.js Vue file is this:
import Vue from 'vue'
import resources from 'vue-resource'
Vue.use(resources)
import App from './components/App.vue'
import style from './styles/main.scss'
/**
* Root Vue instance
* #param {[element]} el: 'body' [Adds to the html body]
* #param {[component]} components: {app: App} [Renders ./component/App]
*/
new Vue({
el: 'body',
components: {
app: App
}
})
And this is the App component:
<template>
<h1>{{ msg }}</h1>
<input v-model="msg">
<button v-on:click="get">Call Server</button>
</template>
<script>
export default {
data: function() {
return {
msg: 'Hello World!'
}
},
methods: {
get: function() {
// GET request
this.$http({
url: 'localhost:8090',
method: 'GET'
}).then(function(response) {
console.log('ok');
}, function(response) {
console.log('failed');
});
}
}
}
</script>
When I click the button I get this error:
XMLHttpRequest cannot load localhost:8090. Cross origin requests are
only supported for protocol schemes: http, data, chrome,
chrome-extension, https, chrome-extension-resource.
When I try to call another server, like google.com, I get this error:
build.js:19188 GET http://localhost:8080/google.com 404 (Not Found)
So it seems like Vue is putting the localhost:8080 in front of the call, and maybe this is where my problem lies? Making server calls is completely new to me, I'm just playing around with Vue and want to learn Node.js while I do so.
This basically has nothing to do with Node or Vue and everything to do with how security in the browser is implemented. CORS is not a workaround. Read up on CORS to see why it is needed. This question of mine, which is quite similar to yours, has some good info in the answers sections as well. To be able to call an API without using CORS it needs to run on the same host, port and protocol, otherwise it will be blocked by your browser.
Years ago, before the advent of CORS, you needed to use JSONP to achieve the same. You can of course have a look at it to see how this works, but nowadays there is very little need for that technique as we have proper cross-domain support in the form of CORS.
Regarding your question in one of the comment sections on "How do people call API's when working with Vue.js?", they do one of the following:
Run the API on another server (such as api.mydomain.com), but set the CORS headers on the response.
As above, but the client and server wraps responses using the JSONP method mentioned above.
Run the API on the same server as the one serving pages. This means api calls will be done against an endpoint such as localhost:8080/api
Twist on #3: just proxy calls coming in on the server to another server. Meaning you can have your api server running elsewhere, but your main server that is accepting calls on /api will just send these requests on the the next server after stripping off the /api prefix. Usually, people either setup an Apache or Nginx instance in front of your app server and do the actual proxying on that, but you can also do it in your app server, using something like node-proxy.
You can probably read this through the lines already, but save yourself some trouble (and time) and just use CORS :) #trquoccuong has the details on doing this in his answer.
CORS problems, you can use cors node module or add request header
if use Express
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if use http module
res.setHeader
Related
I am having some trouble with implementing authorization cookies.
When I make a GET request to my api (which is running on port 8080) from my react frontend (which is running on port 3000), the cookies which I set with express are not received in the frontend.
I'm implementing a subdomain per client type of application, and the cookies are rightfully received on the normal "localhost". However, when I try to use like example.localhost, the cookies are not received at all.
I tried to do it both with axios and normal fetches, and I just can't seem to get it to work.
I used Same-Site, Secure etc and set credentials to true both in CORS and Axios.
Here are a couple snippets:
app.get('/api/dashboard/overview', (req, res) => {
res.cookie("test", "test", {httpOnly: false}); //Already tried Secure etc
res.send('Cookie was set!');
});
getRequest('/dashboard/overview').then(response => {
console.log(response.data);
return response;
});
export function getRequest(url) {
return axios.get(apiUrl + url, {withCredentials: true, headers: { crossDomain: true, 'Content-Type': 'application/json' }});
}
I think the problem lies in the subdomain.localhost stuff, but sometimes the cookies do not load on normal localhost either.
I already tried to add a domain to vhosts, but it did not work either.
Hope one of you guys could help!
If your web server is running on localhost:8080, try to add this property to cors object. Might can do the trick.
origin: 'http://localhost:8080'
I don't know why but I got confused regarding Nodejs one behaviour.
Following is my nodejs code my server is running at port:8080
const express = require("express");
const app = express();
const multer = require("multer");
const cors = require('cors');
app.use(cors({
origin:"http://localhost:4000"
}))
app.get("/userinfo", async (req, res) => {
console.log("reached heree");
res.json({
message: "access",
});
});
app.listen(
8080,
(error) => {
if (error) {
console.log("error");
}
},
() => {
console.log("listening at port 8080");
}
);
And I am trying to hit API from a different origin [localhost:3000]
import logo from './logo.svg';
import './App.css';
import axios from "axios";
function App() {
const makeRequest =()=>{
axios.get("http://localhost:8080/userinfo").then(response=>{
console.log(response);
}).catch((e)=>{
console.log(e);
})
}
return (
<div className="App">
<button onClick={makeRequest}>Click</button>
</div>
);
}
export default App;
But when I click Click when I inspect the code, I got an error message as expected You are blocked by CORS policy.But when I see in terminal on my server-side, I see output Reached here.
At this point, I got too confused and frustrated at the same time. How cross-site request triggered /userinfo from the different origin?. I don't think this should happen.
How can I solve this issue??
It's not your server that is blocking the request. Your server SHOULD send back the HTTP request because servers and WIFI and your router does not care about CORS.
It is the web browser that blocks the CORS. Blocking CORS does not mean you don't hit the server endpoint. It does not even mean that the HTTP packet is blocked. Blocking CORS means your web browser is refusing to let your javascript code from reading the data returned by the server.
The purpose of CORS is to bypass the original Same-origin policy which is still enforced today. The same-origin policy was added when javascript was added to web browsers. It allows web browsers to make HTTP requests but tries to prevent malicious scripts from listening in to HTTP data by disallowing scripts to read the result of HTTP requests (XMLHttpRequest or fetch) unless the URL is from the same domain as the page.
The only thing CORS adds is a header that your server can send back to the browser that tells the browser that it's OK for javascript code to access the result of the HTTP request.
Try to call remote API Url but, getting Access-Control-Allow-Origin error. I tried many things like following but, nothing works.
proxy.conf.js
const PROXY_CONFIG = [
{
context: [
"/api/planets"
],
target: "https://swapi.co",
secure: false,
changeOrigin: true,
logLevel: "debug",
bypass: function (req, res, proxyOptions) {
req.headers["Access-Control-Allow-Origin"] = "*";
req.headers["X-Forwarded-Host"] = "localhost:8090";
req.headers["X-Forwarded-For"] = "localhost";
req.headers["X-Forwarded-Port"] = "8090";
req.headers["X-Forwarded-Proto"] = "http";
}
}
];
module.exports = PROXY_CONFIG;
Running with ng serve --port 8090 --proxy-config proxy.conf.js
Can't make any changes in server side because I am using third party API.
Try adding plugin like https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?hl=en in your chrome browser.
Since you cant change the server side config, so this plugin can do the trick. The browser by default blocks CORS
Since You cannot make any changes on remote server. So it can be escaped using Reverse proxy server. I also faced the same issue while calling linkedin services.
a. There is an https://cors-anywhere.herokuapp.com/ you can append this before your url
and it will temporarily resolve CORS issues.
Since in enterprise scenario you can not use herokuapp.com before your application specific names so better to set below proxy server.
b. Second approach is using rever-proxy approach and set up your own server (local or remote ) for reverse proxying.
https://stackoverflow.com/q/29670703/7562674
You can also implement reverse-proxy like implementation using Spring and Jersey.
https://github.com/hhimanshusharma70/cors-escape
As the error says, a header named Access-Control-Allow-Origin must be present in a CORS response.
Since swapi.co responses include the Access-Control-Allow-Origin header for correct CORS requests (can be tested with a simple fetch('https://swapi.co/api/planets/') from your browser's dev console), the issue may be because of your proxy settings.
Try modifying the response in the proxy bypass method:
bypass: function (req, res, proxyOptions) {
...
// Note that this is "res", not "req".
res.headers["Access-Control-Allow-Origin"] = "*";
...
}
You can't! End of story. If the owner of the api has decided not to allow cross origin requests then you can't. If your are not going to host your app on the https://swapi.co domain then you will not be able to use the api directly from Angular and you will need some kind of pass through api call on the server from .NET, Node, PHP, Java etc.
var express = require('express');
var app = express();
var path = require('path');
var api = require('./api');
app.get('/', function(req, res){
res.sendFile(path.join(__dirname + '/index.html'));
})
app.listen(8080)
console.log('Server Running');
I know that we are requiring the express module. We are using the express function, we are requiring the module path and storing the reference in variable path and doing the same with api but beyond that I am a little lost. If I wanted to connect to twitter API how would I go about doing this? Can someone please explain the logic behind it so i can go learn this better and apply it by myself with different API's? I sincerely and greatly appreciate all of your help!
Express is a framework for organising your web application server. You open up certain API's routes to listen on the path and respond to the requests when necessary.
You can open API's only for internal use, i.e. calls from the browser running your app. Or you can expose your API to outer world (for example twitter API is doing that).
To connect to twitter API you need to make an outgoing request from your webserver. There are many ways to go about that, starting from native nodeJS package http https://nodejs.org/api/http.html to much more popular alternative request https://github.com/request/request
One thing to note here is that NodeJS web server are in general less restrictive than other language servers, especially when it comes to organising your app and code architecture. Hence more issues for beginners. Feel free to ask more questions.
Main purpose of app in
var app = express()
is to listen to routes (it is as well used to render pages, adding middleware etc.) and only that.
So assume u have a button on your UI which allows you to connect to twitter API. So on the click you make a GET request to your own server, to /api/twitter/connect .
On your server you listen on this path as follows:
var request = require('request'); //assuming you installed this module
app.get('/api/twitter/connect', function(req, res){
request(TWITTER_API_URL + API_KEYS, function(err, body){
res.json(body); //res is the response object, and it passes info back to client side
});
});
You can use "request" package to send requests. But in case of Cross-Origin-Request you must use "HTTPS" instead of "HTTP". You can configure Your request according to your request type like this..
//Load the request module
var request = require('request');
//Lets configure and request
request({
url: 'https://example.com/abc/demo', //URL to hit
qs: {from: 'example', time: +new Date()}, //Query string data
method: 'GET', // specify the request type
headers: { // speciyfy the headers
'Content-Type': 'MyContentType',
'Custom-Header': 'Custom Value'
},
body: 'Hello Hello! String body!' //Set the body as a string
}, function(error, response, body){
if(error) {
console.log(error);
} else {
console.log(response.statusCode, body);
}
});
Besides this there are others way to do the same. And for twitter you can also checkout the module called "twitter"
I am creating a web app with Node.js and Express. When I try to upload my project to Heroku, all of my content loads successfully on the page, but I get an error when I try to perform any action that requires an AJAX call to the API I'm working with:
Mixed Content: The page at
'https://farmers-market-finder.herokuapp.com/' was loaded over HTTPS,
but requested an insecure XMLHttpRequest endpoint
http://search.ams.usda.gov/farmersmarkets/v1/data.svc/zipSearch?zip=94118.
This request has been blocked; the content must be served over HTTPS.
I'm working with an API of farmer's market data, made by the USDA, and have followed their suggested format for RESTful AJAX requests:
$.ajax({
type: 'GET',
url: 'http://search.ams.usda.gov/farmersmarkets/v1/data.svc/mktDetail?id=' + id,
async: false,
success: function (data) { ... }
})
I have done a lot of research on Stack Overflow and other sites about this Mixed Content error. Most answers suggest that the 'GET' request route needs to be changed to "https://..." in order to work on Heroku's https server. I tried switching this, but the route to the API no longer works; I get a 404 Not Found error. I also tried switching my route to a relative link (just writing url: '//search.ams...') but that got the same 404 error. Seems like I really do need an http:// link to reach the API I'm trying to access.
Does anyone know of a way to get Heroku to allow me to use an "http" link, instead of https, or some other way to successfully make the request?
In your server.js file, add this code above your other app.use statements. (App = expr
app.use(function (req, res, next){
if (req.headers['x-forwarded-proto'] === 'https') {
res.redirect('http://' + req.hostname + req.url);
} else {
next();
}
});