I am developing an application with Ionic Framework Version 3.19.1, I am making a request via post, the URL data, and necessary parameter information is all ok, however, it is returning an error that I can not solve, I have tried many ways, imports into the project, but without success. below is my post function.
const req = this.http.post(url, {
options: {
headers:[header],
params:[postData]
}
}).subscribe(
res => {
console.log(res);
},
err => {
console.log('Ocorreu um erro');
}
)
Below are my imports inside the .ts file (TypeScript)
import { Component } from '#angular/core';
import { TranslateService } from '#ngx-translate/core';
import { IonicPage, NavController, ToastController } from 'ionic-angular';
import { HttpClient, HttpParams, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { IonicStorageModule } from '#ionic/storage';
import { User } from '../../providers/providers';
import { MainPage } from '../pages';
Well, as I said I'm doing a post request and on the console, it returns an OPTIONS 500 (Internal Server Error)
Failed to load (URL): Response to preflight request does not pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http: // localhost: 8100' is therefore not allowed access. The response had HTTP status code 500.
by what I understand is reporting a problem regarding the Header, but I have already informed the correct one and left the requests open, but it still does not work, here is my header below.
const header = new HttpHeaders();
header.set('Access-Control-Allow-Origin', '*');
header.set('Content-type', 'application/json');
change the const req
return new Promise((resolve, reject) => {
this.http.post(url, postData,
{headers: this.header})
.subscribe(
data => {
console.log('success');
resolve(data);
},
err => {
reject(err);
console.log(err);}
);
});
Related
I was creating authentication mechanism for my service. And at some moment I had problem with cookies. More you can find here, so I solved this.
The problem was that I was trying to send cookie through 2 requests. My Next.js front-end sends request to its internal API, and only then, internal API sends this request to back-end.
The solution of this problem was very easy, what I had to do - is to set cookie on back-end and return it in headers. Here is how flow looks, like.
This is how it looks like, endpoint in Next.js front-end. Except of data in response, it receives header, where cookie is set (response from back-end) and send it in header of response, that will be send on front-end, where cookie will be set:
import { NextApiRequest, NextApiResponse } from "next";
import { AxiosError } from "axios";
import { api } from "../../../api";
export default async (
req: NextApiRequest,
res: NextApiResponse
) => {
try {
const { data, headers } = await api.post('/user/sign-in', req.body)
if (headers["set-cookie"]) {
res.setHeader("Set-Cookie", headers["set-cookie"]);
}
return res.json(data)
} catch (error) {
return res
.status((error as AxiosError).response?.status as number)
.json((error as AxiosError).response?.data);
}
}
And endpoint on back-end:
import { Response as Res } from 'express';
import * as dayjs from 'dayjs';
...
async signIn(#Body() signInUserDto: SignInUserDto, #Response() res: Res) {
const { _at, _rt } = await this.userService.signIn(signInUserDto);
res.cookie('_rt', _rt, {
httpOnly: true,
expires: dayjs().add(7, 'days').toDate()
});
return res.send(_at);
}
And here is the problem, because of this Response class of express I keep getting this warning:
Error: This is caused by either a bug in Node.js or incorrect usage of Node.js internals.
Please open an issue with this stack trace at https://github.com/nodejs/node/issues
at new NodeError (node:internal/errors:371:5)
at assert (node:internal/assert:14:11)
at ServerResponse.detachSocket (node:_http_server:249:3)
at resOnFinish (node:_http_server:819:7)
at ServerResponse.emit (node:events:390:28)
at onFinish (node:_http_outgoing:830:10)
at callback (node:internal/streams/writable:552:21)
at afterWrite (node:internal/streams/writable:497:5)
at afterWriteTick (node:internal/streams/writable:484:10)
at processTicksAndRejections (node:internal/process/task_queues:82:21)
It is definitely because of how this signIn function looks like, because I was trying to return just like this - return this.userService.signIn(signInUserDto) - and it worked, but I can't cookie in this case.
So, my question is - what is this error? Can I just ignore it? If not, then how can I fix it?
Thanks in advance!
TL;DR
Finally, I was able to fix this error, first of all, as I said, my goes through 2 API's, from back-end to front-end API, and only then, this front-end API sends this request to actual front-end.
So, what I did, is just returned 2 tokens - refresh and access - as body.
#ApiOperation({ summary: 'Resource for sign in user.' })
#ApiResponse({ status: 200, type: TokensDto })
#Post('/sign-in')
async signIn(#Body() signInUserDto: SignInUserDto) {
return this.userService.signIn(signInUserDto);
}
Then, on front-end, I installed cookie and #types/cookie and in this front-end endpoint, in headers, I just serialized this refresh token from body payload, and removed from it.
import { NextApiRequest, NextApiResponse } from "next";
import { AxiosError } from "axios";
import { api } from "../../../api";
import { serialize } from 'cookie';
export default async (
req: NextApiRequest,
res: NextApiResponse
) => {
try {
const { data } = await api.post('/user/sign-in', req.body)
res.setHeader('Set-Cookie', serialize(
'_rt',
data._rt,
{ path: '/', httpOnly: true })
);
delete data._rt
return res.json(data)
} catch (error) {
return res
.status((error as AxiosError).response?.status as number)
.json((error as AxiosError).response?.data);
}
}
And it works perfectly fine, I don't have this Node.js error any more because of response with Express response class, and I'm able to set cookie.
EDIT
I have improved this code in even better way by using fastify and in the whole pipeline cookie is set in header. First of all, on back-end install #fastify/cookie and #nestjs/platform-fastify. Then, add this in file, where you start you Nest.js app:
import {
FastifyAdapter,
NestFastifyApplication
} from '#nestjs/platform-fastify';
import { fastifyCookie } from '#fastify/cookie';
async function bootstrap() {
const PORT = process.env.PORT || 3002;
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter()
);
await app.register(fastifyCookie, {
secret: 'my-secret'
});
This will allow you to use FastifyReply from fastify, this will eliminate this Node.js error as response class:
import { FastifyReply } from 'fastify';
#ApiTags('User')
#Controller('user')
export class UserController {
constructor(private userService: UserService) {}
#Post('/sign-in')
async signIn(
#Body() signInUserDto: SignInUserDto,
#Res({ passthrough: true }) res: FastifyReply
) {
const { _at, _rt } = await this.userService.signIn(signInUserDto);
res.setCookie('_rt', _rt);
return res.send(_at);
}
...
And the last step, on front-end endpoint, using cookie, parse this cookie and send it to front.
const { data, headers } = await api.post('/user/sign-in', req.body)
if (headers["set-cookie"]) {
const refreshToken = headers["set-cookie"][0].split('=')[1];
res.setHeader('Set-Cookie', serialize(
'_rt', refreshToken, { path: '/', httpOnly: true })
);
}
return res.json(data)
And this is the best way, that I've found, because it allows you to send cookie in header though all pipeline, not in body and then delete it, and this solution eliminates this strange Node.js error.
I am trying to modify response header or an API request that goes from my Angular Application. What I have done is I have created a RequestTracker interceptor which extends HttpInterceptor and adds Correlation-Id to request header. What I want is the same Correlation-Id to be part of the response header. I tried the below interceptor but it isn't working for me. Is there anything I am missing?
import * as uuid from 'uuid';
import {
HttpEvent,
HttpHandler,
HttpHeaders,
HttpInterceptor,
HttpRequest,
HttpResponse
} from '#angular/common/http';
import { filter, map } from 'rxjs/operators';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
#Injectable()
export class RequestTracker implements HttpInterceptor {
intercept(
httpRequest: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const correlationId = uuid.v4();
const httpRequestClone = httpRequest.clone({
setHeaders: {
'Correlation-Id': correlationId
}
});
return next.handle(httpRequestClone).pipe(
filter((response) => response instanceof HttpResponse),
map((response: HttpResponse<any>) => {
const modifiedResponse = response.clone({
headers: response.headers.set('Correlation-Id', correlationId)
});
return modifiedResponse;
})
);
}
}
In Request Headers, the Correlation-Id is getting appended but not in Response Headers.
The response that you have posted, is from the network tab and it refers to the response sent from the server. You are attaching the header once Angular starts processing that response. So it won't be shown in the network tab. Try logging the response inside the code. And correlationId will be part of the response header.
This question already has an answer here:
Access to XMLHttpRequest at 'https://api-v3.igdb.com/games...' ... No 'Access-Control-Allow-Origin' header is present on the requested resource
(1 answer)
Closed 1 year ago.
Despite this being a very common problem, the solutions I've searched don't seem to fix this for me.
import React from "react";
import axios from "axios";
class GamesList extends React.Component {
componentDidMount = async () => {
const response = await axios.get("https://api-v3.igdb.com/games", {
headers: {
"user-key": "<API-KEY>",
"Access-Control-Allow-Origin": "http://localhost:3000",
},
});
console.log(response);
};
render() {
return <div>MANY GAMES</div>;
}
}
export default GamesList;
The error messages I receive from running this code is:
Access to XMLHttpRequest at 'https://api-v3.igdb.com/games' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET https://api-v3.igdb.com/games net::ERR_FAILED
uncaught (in promise) Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:83)
I've also tried setting "Access-Control-Allow-Origin": "*" though the error doesn't change.
Is there a simple fix for this that doesn't require using/creating a proxy?
--- UPDATE ---
following #HMR's comment, I've edited the code below as per igdb's documentation, though I'm still getting the same error. Where am I going wrong with this?
import React from "react";
import axios from "axios";
class GamesList extends React.Component {
componentDidMount = async () => {
// As mention in the docs, I'm using POST with the necessary body
axios.post("https://api-v3.igdb.com/headers", {
body: {
api_header: {
header: "Access-Control-Allow-Origin",
value: "*",
},
},
});
// now to make the actual request
const response = await axios.get("https://api-v3.igdb.com/games", {
headers: {
"user-key": "<API-KEY>",
"Access-Control-Allow-Origin": "http://localhost:3000",
},
});
console.log(response);
};
render() {
return <div>MANY GAMES</div>;
}
}
export default GamesList;
Even posting the following to https://api-v3.igdb.com/headers/ inside of postman returns Not found:
{
"api_header": {
"header": "Access-Control-Allow-Origin",
"value": "*"
}
}
-- FINAL UPDATE --
As #goto1 and #HMR have mentioned below, the api itself doesn't seem to support CORS correctly.
I've ended up going with a proxy in the end! I'm using https://github.com/Rob--W/cors-anywhere/ (NOTE: I had to npm install proxy-from-env manually)
After starting up the server using node server.js, I can prepend the server's address to my igdb api request. Final code:
import React from "react";
import axios from "axios";
class GamesList extends React.Component {
componentDidMount = async () => {
const response = await axios.get("http://0.0.0.0:8080/https://api-v3.igdb.com/games", {
headers: {
"user-key": "<API-KEY>",
},
});
console.log(response); // WORKS!
};
render() {
return <div>MANY GAMES</div>;
}
}
export default GamesList;
Did you try ti set localhost:3000 in package.json instead in axios headers
TL;DR;
Why subscribing to an Observable in an http interceptor produces duplicate http requests to server?
Sample code:
doGetWithInterceptor() {
console.log("Http get with interceptor -> 2 http calls ?? Why?");
this.http_interceptor_get("http://ip.jsontest.com/").subscribe(data => {
console.log("But only one block of data received:", data);
this.result= data.ip;
});
}
http_interceptor_get(url : string) {
let req= this.http.get(url).map(res => res.json());
req.subscribe((data) => {
console.log("[HttpInterceptor]");
});
return req;
}
Full details:
I use an http interceptor service in my Ionic 2 project to globally detect errors, authentication, and more...
But doing so, I am seeing duplicate http requests to the server.
I have an small test App starting from a blank Ionic 2 template:
Which clearly shows the problem in Firebug:
First request (it's ok, single) if using the GET button.
Second request (which duplicates) is using the "Get with interceptor" button.
Meanwhile, the code in the subscription part is executed only once, as it should.
The home.ts code is as follows:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
result : string = "???";
constructor(public navCtrl: NavController, public http: Http) {
}
http_get(url : string) {
return this.http.get(url).map(res => res.json());
}
http_interceptor_get(url : string) {
let req= this.http.get(url).map(res => res.json());
req.subscribe((data) => {
console.log("[HttpInterceptor]");
});
return req;
}
doGet() {
console.log("Normal http get -> 1 http call");
this.http_get("http://ip.jsontest.com/").subscribe(data => {
console.log("One block of data received:", data);
this.result= data.ip;
});
}
doGetWithInterceptor() {
console.log("Http get with interceptor -> 2 http calls ?? Why?");
this.http_interceptor_get("http://ip.jsontest.com/").subscribe(data => {
console.log("But only one block of data received:", data);
this.result= data.ip;
});
}
doClearResult() {
this.result= "???";
}
}
Its because you are not really intercepting. You are simply subscirbing to the request twice.
http_interceptor_get(url : string) {
let req= this.http.get(url).map(res => res.json());
req.subscribe((data) => { //1st subscription - 1st call
console.log("[HttpInterceptor]");
});
return req; //return original request
}
Then you are subscribing again in doGetWithInterceptor() to your http req.
If you want to log details of call, you can use do().
http_interceptor_get(url : string) {
//return http call
return this.http.get(url).map(res => res.json())
.do(data=>{
//do checks.
return data; //be sure to return data so it is passed on to subscription.
});
}
Then call in your doGetWithInterceptor()
I'm having a hard time getting a good response from the tumblr api on a GULP localhost.
using postman, I get the proper response from the request URL:
http://api.tumblr.com/v2/blog/{any_blog}/posts?limit=5&api_key={key}
I can't seem to get the response in my aurelia module though. I keep getting the error
Fetch API cannot load http://api.tumblr.com/...........
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost' is therefore not allowed access.
Code is below:
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';
import 'fetch';
#inject(HttpClient)
export class Users{
heading = 'Blog Posts';
posts = [];
constructor(http){
http.configure(config => {
config
.withBaseUrl('http://api.tumblr.com/v2/')
.withDefaults({
headers: {
'Access-Control-Allow-Origin': '*'
}
});
});
this.http = http;
}
activate(){
return this.http.fetch('blog/{blog_name}.tumblr.com/posts', { limit: 5, api_key: {api_key} })
.then(response => response.json())
.then(posts => this.posts = posts);
}
}
This is CORS limitation. You can't make cross-domain requests if your origin is not granted permission. It works for server-side requests of course, that's why you can fetch data without problem in case of nodejs request.
To workaroud the problem you should make use of JSONP approach supported by Tumblr. You would also use HttpClient for jsonp method.
In your case code will be:
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-http-client';
#inject(HttpClient)
export class Users{
heading = 'Blog Posts';
posts = [];
constructor(http){
http.configure(config => {
config
.withBaseUrl('http://api.tumblr.com/v2/')
.withParams({
limit: 5,
api_key: '{api_key}'
});
});
this.http = http;
}
activate(){
return this.http.jsonp('blog/{blog_name}.tumblr.com/posts', 'jsonp')
.then(httpResponse => this.posts = httpResponse.response.response.posts);
}
}