I have a a spring boot backend that validates user login credentials. After validating the user it sends a login token in its response header. This part definitly works because I have seen it work in postman:
Now I am trying to get the token into my vuejs front end by doing the following:
import axios from 'axios'
const databaseUrl = 'http://localhost:9090/api'
const datbaseUrlBase = 'http://localhost:9090'
async function getSubjects(){
const result = await axios.get(`${databaseUrl}/subject`)
return result.data
}
async function updateSubject(subject){
let body = {
"name": subject.name,
"first_name": subject.first_name,
"date_of_birth": subject.date_of_birth
}
let result = await axios.put(`${databaseUrl}/subject/${subject.subjectid}`, body)
return result.data
}
async function getSubject(id){
let result = await axios.get(`${databaseUrl}/subject/${id}`)
return result.data
}
async function getSimulationsForSubject(id){
let result = await axios.get(`${databaseUrl}/subject/${id}/simulation`)
return result.data
}
async function deleteSubject(id){
await axios.delete(`${databaseUrl}/subject/${id}`)
}
async function makeSubject(subject){
await axios.post(`${databaseUrl}/subject`, subject)
}
async function updateDiagnose(diagnose, id){
await axios.put(`${databaseUrl}/subject/${id}/diagnose/${diagnose.diagnoseid}`, diagnose)
}
async function addSymptomToDiagnose(symptom, diagnoseid, subjectid){
await axios.post(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}/symptom`, symptom)
}
async function updateSymptom(symptom_id, symptom, subjectid, diagnoseid){
await axios.put(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}/symptom/${symptom_id}`, symptom)
}
async function getDiagnoseForSubject(diagnoseid, subjectid){
let result = await axios.get(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}`)
return result.data
}
async function deleteSymptomForDiagnose(subjectid, diagnoseid, symptomid){
await axios.delete(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}/symptom/${symptomid}`)
}
async function getStatisticsForSimulation(subjectid, simulationid){
let result = await axios.get(`${databaseUrl}/subject/${subjectid}/simulation/${simulationid}/statistics`)
return result.data
}
async function login(login){
let result = await axios.post(`${datbaseUrlBase}/login`, login)
return result.headers
}
export default{
getSubjects,
updateSubject,
getSubject,
getSimulationsForSubject,
deleteSubject,
makeSubject,
updateDiagnose,
addSymptomToDiagnose,
getDiagnoseForSubject,
deleteSymptomForDiagnose,
updateSymptom,
getStatisticsForSimulation,
login
}
Notice the login function above. Whenever I run this code the console.log gives undefined in the browser.
And the console.log(result.headers) gives this:
Is there anyway of accessing this token in my vuejs frontend?
If the server is cross-origin then browser CORS dictates that only a handful of default headers are accessible in a response.
You need to either have a matching origin, or enable the Access-Control-Expose-Headers header by setting it in your response like this:
Access-Control-Expose-Headers: token
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
Related
I'm figuring out how data fetching works in Next.js 13 and I noticed that this code, when revalidating a fetching current data, makes two HTTP requests to the server instead of one. The requests go right after each other.
async function getData() {
const url = `${process.env.API_URL}/public/monitoring/websocket/`
const res = await fetch(url, {next: {revalidate: 10}})
if (!res.ok) {
throw new Error('Failed to fetch data')
}
return res.text()
}
export default async function Home() {
const data = await getData()
return (<div>{data}</div>)
}
Q: Is there any reason why there are two HTTP requests to the server?
I have ApolloServer running where the frontend makes a query request and the ApolloService fetches the request and then performs a request with RESTDataSource to a third-party service, I receive a response with a header.
Currently, ApolloServer only parses the body through the resolver and sends it back to the client
I wanted to pass also the header received to the client
I don't know how to do that at the RESTDataSource level since I don't have access to the Apollo response
I hope this was clear enough to explain the problem
export abstract class myClass extends RESTDataSource {
getSomething() {
const endpoint = this.endpointPath;
return this.get(endpoint);
}
async didReceiveResponse<T>(response, request): Promise<T | null> {
// these are the response headers desired to have them sent back to the client
console.log(response.headers);
if (response.ok) {
return this.parseBody(response) as any as Promise<T>;
} else {
throw await this.errorFromResponse(response);
}
}
}
In the appolloService initialization i have
const apolloServer = new ApolloServer({
context: async ({ res, req }) => {
// these headers are not the same as received from the getSomething() response above
console.log(res.getHeaders)
}
)}
I solved the issue by passing the res to the context and accessing the response in the didReceiveResponse, then adding the headers needed.
adding a response to context
const apolloServer = new ApolloServer({
context: async ({ res, req }) => {
return {
res: res,
};}
using the response to append the headers to it
async didReceiveResponse<T>(response, request): Promise<T | null> {
// use this.authHeader value in the class anywhere
this.context.res.setHeader(
"x-is-request-cached",
response.headers.get("x-is-request-cached") ?? false
);
this.context.res.setHeader(
"x-request-cached-time",
response.headers.get("x-request-cached-time")
);
if (response.ok) {
return (await this.parseBody(response)) as any as Promise<T>;
} else {
throw await this.errorFromResponse(response);
}}
by doing this you will achieve the desired outcome of passing the headers to the graphQl client
I am trying to send an image to Next.js api and then use that image to upload to db.
I am using :
const body = new FormData();
body.append("file", prewiedPP);
const response = await fetch("/api/send-pp-to-server", {
method: "POST",
body ,
headers: {
iext: iExt,
name: cCtx.userDetail ,
},
});
Then in the api :
async function handler(req, res) {
if (req.method === "POST") {
console.log("In");
const form = new formidable.IncomingForm();
form.parse(req,
async (err, fields, files) =>
{
// console.log(req.headers.iext);
// console.log(req.headers.name);
const fdata = fs.readFileSync(files.file.filepath);
await delUserPP(req.headers.name , req.headers.iext);
await setUserPP(
fdata ,
req.headers.name ,
req.headers.iext ,
files.file.mimetype
);
fs.unlinkSync(files.file.filepath);
return;
});
console.log("out");
}
}
export default handler;
The callback function in the from.parse happens after the handler already resolved.
Is there anyway to make the api call only resolve after the setUserPP function is done?
I want to send a response back to the client but the api script finishes to "fast" and before the callback in form.parse runs.
Thanks
I have an issue with the authentication process of a websocket route.
I'm using PassportJS with 'local' strategy.
Logging in and calling normal API Routes are perfectly working with #AuthenticatedGuard,
but not on websockets
On the Websocket Route, it is throwing following error:
ERROR [WsExceptionsHandler] request.isAuthenticated is not a function
TypeError: request.isAuthenticated is not a function
This is my setup:
Example normal working API Route
test.controller.ts
#UseGuards(AuthenticatedGuard)
#Get(':id')
async findOne(
#Param('id') id: string,
#Req() req: any,
#Res() res: Response,
) {
return res.json(
await this.testService.findOne(+id),
);
}
Websocket Route
messages.gateway.ts
#UseGuards(AuthenticatedGuard)
#SubscribeMessage('findAllMessages')
async findAll(
#ConnectedSocket() client: Socket,
#MessageBody() findAllMessages: findAllMessages,
#Req() req: any,
) {
console.log(req);
//return this.messagesService.findAll(chatroomid);
const user = await this.messagesService.checkCurrentSessionString(
req.handshake.headers.cookie,
);
if (req.user.userid != undefined) {
return await this.messagesService.findAll(findAllMessages, user.userid);
} else client.disconnect(true);
throw new UnauthorizedException({
statusCode: 401,
message: 'Bitte logge dich erst ein',
});
}
authenticated.guard.ts
#Injectable()
export class AuthenticatedGuard implements CanActivate {
async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
return request.isAuthenticated();
}
}
Seems like the session is not valid for the websocket routes?
I have a lambda function that returns a message to the client.
function replyToMessage (messageText,connectionId) {
const data = {message:messageText}
const params = {
ConnectionId : connectionId,
Data: Buffer.from(JSON.stringify(data))
}
return api.postToConnection(params).promise()
.then(data => {})
.catch(error => {console.log("error",error)})
}
This code is called once when the connection is made and I get a response to my client. When I call the function again with a different endpoint, it doesn't send a response to my client. However, when I call it a third time, I get the response to my client from the second call. Here's my switch when the Lambda function is called.
switch(route) {
case "$connect":
break
case "$disconnect":
break
case "connectTo":
await connectToService(JSON.parse(event.body).eventId,connectionId)
await replyToMessage("Connected eventId to connId",connectionId)
break
case "disconnectFrom":
await disConnectToService(JSON.parse(event.body).eventId,connectionId)
break
case "project":
responseItems = await getBroadcastIds (JSON.parse(event.body).eventId,JSON.parse(event.body).sourceId,connectionId)
console.log(responseItems)
responseItems.Items.forEach(async function(item) {
await replyToMessage(JSON.parse(event.body).sourceId,item.connectionId)
})
responseItems = []
break
default :
console.log("Unknown route", route)
The issue appears to be the async forEach loop. Switching to the following resolves the issue.
for (const item of responseItems.Items) {
console.log("Sending to:",item.connectionId);
await replyToMessage(JSON.parse(event.body).sourceId,item.connectionId)
}
See this post for the answer that led to this resolution. Using async/await with a forEach loop