Response with status: 0 for URL: null - service

I have a service that do post. The service is being hosted in another machine. When I tried to post using Postman, it works fine. Now, when I tried to post using my Angular2 app which is run in another machine I got an error "Response with status: 0 for URL: null." The code in my angular service is as follows:
postQuestions() {
var json = JSON.stringify({
"TestInfo_FK" : "612",
"Resource_FK" : 0,
"QuestionNo" : 22,
"ContentType" : "HTML",
"Content" : "This is the question from Jason",
"NoOptions" : 4,
"OptionLayout" : "Vertical",
"Answer" : "A"
});
var url = 'http://my.service.net/api/ONLINE/Question';
var params = 'json=' + json;
var headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Access-Control-Allow-Origin', '*');
return this._http.post(url, params, {
headers: headers
})
.map(res => res.json());
}
how to solve this issue?

This situation arises when your hosted service is not able to be accessed via cross origin(CORS) .So if u you are accessing Spring Rest service then use #CrossOrigin annotation on service.
OR use
flask-restful to build remote API
from flask_restful.utils import cors
from flask_restful import Api
api = Api(app, decorators=[cors.crossdomain(origin='*')])

I found out what was causing the issue.. Its a server side issue. You need to set the CORS middleware first then the remaining API middlewares.
Please note i am working with Laravel 5.6 + Angular 5
Wrong Code
'api' => [
'throttle:60,1',
'bindings',
\Barryvdh\Cors\HandleCors::class,
],
Currect Code
'api' => [
\Barryvdh\Cors\HandleCors::class,
'throttle:60,1',
'bindings'
],

Related

Can't set Access-Control-Allow-Credentials header for REST API

I'm having the following issues:
I need to allow CORS only on a specific domain
I need to make sure that secure cookies are sent along with the cross-origin request.
API Gateway specifies '*' as the Access-Control-Allow-Origin header and I need to only allow "example.com".
I found that I can do this by adding the following in override.ts in the rest API resource folder:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
// Change the default CORS response header Access-Control-Allow-Origin from "'*'" to the API's domain
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Origin'] = {
'Fn::Sub': "'https://www.example.com'"
};
}
This seems unreasonably hacky, but whatever.
But I can't seem to solve for the Access-Control-Allow-Credentials header... This doesn't work:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
// Change the default CORS response header Access-Control-Allow-Origin from "'*'" to the API's domain
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Origin'] = {
'Fn::Sub': "'https://www.example.com'"
};
// ADDING THIS ...
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = "true";
}
I get multiple errors, but it's basically complaining with this error for each of my REST endpoints:
Unable to put integration response on 'OPTIONS' for resource at path '/oauth/hubspot': Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: true]
I get similar errors if I try any of the following:
// with quotes inside quotes
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = "'true'";
// this structure
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = {
'Fn::Sub': "'true'"
};
The thing is, I could easily do all this myself if Amplify would just let me override how I handle the OPTIONS request, and send it to my lambda function....
VICTORY!
I'd still be interested in any suggested approaches, but this worked for me:
// This file is used to override the REST API resources configuration
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
delete resources.restApi.body.paths['/v1'].options;
delete resources.restApi.body.paths['/v1/{proxy+}'].options;
}
Basically, it's me telling Amplify to get out of the way and let me handle the OPTIONS request myself. So this leaves the "ANY" method on the endpoint so that the OPTIONS request flows through to the LAMBDA that's already configured. I already had the code in there to handle OPTIONS requests, so... It. Just. Worked.
I know it's been six months since you asked this question, but it's something i've just been smashing my head against now.
I had exactly the same issue:
I need CORS across several domains, but I can't use Access-Control-Allow-Origin: '*' because in the browser I am calling the api with { withCredentials: true }.
My Api's back into a lambda function which correctly handles the CORS preflight on the OPTION request. (ie. it returns Access-Control-Allow-Origin: https://permitted.origin.goes.here and associated headers).
But I get CORS errors because the AWS API Gateway response for OPTION is using a predefined MOCK response, which does not allow any other value for Access-Control-Allow-Origin than '*'.
(this was all generated by Amplify).
Anyways, I tried your method of deleting the OPTION handler, but that still did not work for me.
Eventually, after configuring it correctly in the AWS API Gateway interface, exporting the swagger and replicating that in the override.ts file, I finally got it cleanly working.
this was my code in override.ts:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
const { paths } = resources.restApi.body;
Object.keys(paths).forEach((path) => {
if (!!paths[path].options) {
const uri = paths[path]['x-amazon-apigateway-any-method']['x-amazon-apigateway-integration'].uri;
paths[path].options = {
"responses" : {
"200" : {
"description" : "200 response",
"headers" : {
"Access-Control-Allow-Credentials" : {
"type" : "string"
},
"Access-Control-Allow-Origin" : {
"type" : "string"
},
"Access-Control-Allow-Methods" : {
"type" : "string"
},
"Access-Control-Allow-Headers" : {
"type" : "string"
}
}
}
},
"x-amazon-apigateway-integration" : {
"httpMethod" : "POST",
"uri" : uri,
"responses" : {
"default" : {
"statusCode" : "200"
}
},
"passthroughBehavior" : "when_no_match",
"contentHandling" : "CONVERT_TO_TEXT",
"type" : "aws_proxy"
}
}
}
});
}
Now I can return secure cookies to a browser app from the AWS REST API without choking on CORS errors.
good luck!

how to send apikey when using IBM Cloud API?

I'm trying to call IBM cloud speech to text API directly from my angular project.
getAudioFile (text: string) {
return this.http.post(this.apiUrl, {
text: text
}, {
headers: {
'Content-Type' : 'application/json',
'Accept' : 'audio/wav',
'authorization' : 'apikey:' + this.apiKey
},
params: {
voice: 'en-US_AllisonV3Voice'
}
}).pipe(map(res => console.log(res)), catchError(this.handleError))
}
I got the apiKey and apiUrl from the website specifically for my account (which works as a token). I'm just not sure if I'm sending it the right way. Please help me if you have done this before.
See the API documentation and its authentication section. If you want to use the API key, then it is used with Basic access authentication. The username would be "apikey", the password the actual API key. The username and password are base64 encoded. Conceptually, your code would need to look like this:
'Authorization' : 'Basic ' + Base64Encoded("apikey"+this.apiKey)

Axios sending OPTIONS instead GET

I'm trying to make api calls locally in a react app using axios.
I've already added django-cors-headers and followed the documentation, but it does not seem to be working.
I always get the error:
localhost/:1 Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/todos/' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
my base.py:
INSTALLED_APPS = [
# ...
"corsheaders",
"rest_framework",
"todo",
"api",
]
MIDDLEWARE = [
# ...
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
# ...
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = False
In my react app:
const [todos, setTodos] = useState({})
useEffect(
() => {
axios.get(
api_url, {
headers: {
"Access-Control-Allow-Origin": "*",
}
}
).then(
res => {
setTodos(res.data);
console.log(res.data)
}
).catch(
err => {
console.log(err)
}
)
}, []
)
Note, even without configuring a whitelist and reverting the CORS settings to:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
I still manage to get the data in a get call using httpie, just running http + url.
Note 2: When the axios tries to get the data, I get this on the terminal running the Django app:
[04/Jun/2019 18:15:29] "OPTIONS /api/todos/ HTTP/1.1" 200 0
IMPORTANT EDIT:
The problem does not seem to be with my server, I used fetch instead of Axios and everything occurred normally. With Axios, my server was getting an OPTIONS method, and, I do not know why, I was giving this problem with CORS.

Unable to POST using Angular 7 : Header Does not work

I'm currently building out an Angular 7 App, and trying to implement the following HTTP API Call Scenario:
Request for an Application Token:
https://(URL)/token
Request Type: POST
Headers:
Accept: application/json
Request Body: empty
I have a Service class in the Angular app and the code is as follows:
import { HttpClient } from '#angular/common/http';
import { HttpHeaders } from '#angular/common/http';
The requestToken function is implemented as follows:
requestToken() {
let headers = new HttpHeaders();
headers = headers.set('Accept', 'application/json');
return this.http.post(this.configUrl + '/token', headers);
}
The Service is then called in one of the components in the App:-
getToken() {
this.service.requestToken().subscribe( res => {
console.log(res);
}, error => {
console.log(error);
});
}
When I run the App, I get a 404 Not Found error in the console. I used Postman to make an API call, setting the 'Accept' header to 'application/json' and then specifying url as https://(URL)/token and I successfully get a response. But I'm unable to make it work via Angular.
Is there something else I need to do to set the header properly in Angular? Also, I have no way to check if CORS has been enabled on the API server as this is a third-party service which I'm trying to call.
Any help would be appreciated. Thanks
Solved the problem. Changed the POST call to the following:
requestToken() {
const httpHeaders = new HttpHeaders({
'Accept': 'application/json'
});
return this.http.post(this.configUrl + '/token', { body: ''}, { headers: httpHeaders });
}
Had to add an empty 'body' parameter

Atmosphere request.onOpen never gets called. Client-Server connection stopped showing: "101 switching protocols"

I have downloaded the "atmosphere-chat" (jersey) and modified a little because I wanted it to be running inside Jetty.
Everithing is working on this side (in stand alone way). Atmosphere 2.2.0-RC3 / Jetty jetty-9.2.0.M1
But when I put those inside Mule the request.onOpen is never called.
Here is the piece of javascript code (I didn't change from the example):
var request = { url: 'http://myIP:8080/sc.eco/servlet/chat/',
contentType : "application/json",
logLevel : 'debug',
transport : 'websocket' ,
trackMessageLength : true,
fallbackTransport: 'long-polling'};
request.onOpen = function(response) {
content.html($('<p>', { text: 'Atmosphere connected using ' + response.transport }));
input.removeAttr('disabled').focus();
status.text('Choose name:');
};
It's shown on the console "Websocket successfully opened":
but it's stacked in this request:
Request URL:ws://myIP:8080/sc.eco/servlet/chat/?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.2.1-jquery&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&Content-Type=application/json&X-atmo-protocol=true
Request Method:GET
Status Code:101 Switching Protocols
¿Any idea? :S
I had the same problem. I could resolve this by setting enableProtocol to false in the request config.
In your case this would look like this:
var request = { url: 'http://myIP:8080/sc.eco/servlet/chat/',
contentType : "application/json",
logLevel : 'debug',
transport : 'websocket' ,
trackMessageLength : true,
fallbackTransport: 'long-polling',
enableProtocol: false };
I came to this solution was originally proposed in this thread.