Returning NextResponse with modified responses and modified NextRequest - next.js

As per the changelists, it's now possible to modify requests in middleware via:
const headers = new Headers(request.headers);
// Add a new request header
headers.set('x-hello-from-middleware', 'foo');
// Delete a request header from the client
headers.delete('x-from-client');
const resp = NextResponse.next({
// New option `request.headers` which accepts a Headers object
// overrides request headers with the specified new ones.
request: {
headers
}
});
This works fine.
It's also possible to add to to the response, such as adding cookies, via:
let response = NextResponse.next();
response.cookies.set({
name: 'access_token',
value: newAccessToken,
expires: expiresString,
path: '/',
});
return response
This also works fine.
Question
I'm having trouble understanding the technique to combine both.
If I modify the request, for returning. Ideally, I would create the headers object, as in the first example, and then add it to the response object in the second example, before returning response. Seems straightforward. Response is an object.
But I specify:
response.request = headers
or
attempt to make an object or response parameters and and add them alongside header parameters like:
const resp = NextResponse.next({
response: responseParams
request: {
headers
}
});
Neither work. I'm missing something obvious I can't find in the documentation. Any idea?

I didn't find a way to directly set response.request headers after declaring response (perhaps it's not possible) but I did overlook I could change the order I was doing things in and missed the obvious that I could also declare a new NextResponse with request variables as its own variable to add cookies to.
e.g.
let response = NextResponse.next({
request: {
headers: requestHeaders,
}
});
response.cookies.set({
name: 'access_token',
value: newAccessToken,
expires: expiresString,
path: '/',
});
return response
This solved the problem.

Related

Sending a Post Request from Ballerina

I want to send a post request using ballerina to get a access token from the Choreo Dev Portal. I am able to do it using postman. But unable to make it work in Ballerina code level. it gives 415 - unsupported media type error. Need some Help in Ballerina
import ballerina/http;
import ballerina/io;
import ballerina/url;
public function main() returns error? {
final http:Client clientEndpoint = check new ("https://sts.choreo.dev");
http:Request request = new();
string payload = string`grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
subject_token=*******&
subject_token_type=urn:ietf:params:oauth:token-type:jwt&
requested_token_type=urn:ietf:params:oauth:token-type:jwt`;
string encodedPayload = check url:encode(payload, "UTF-8");
io:print(encodedPayload);
request.setTextPayload(encodedPayload);
request.addHeader("Authorization","Basic *****");
request.addHeader("Content-Type","application/x-www-form-urlencoded");
io:print(request.getTextPayload());
json resp = check clientEndpoint->post("/oauth2/token",request);
io:println(resp.toJsonString());
}
I was expecting an access token from Choreo Devportal for the particular application.
import ballerina/http;
import ballerina/io;
import ballerina/mime;
public function main() returns error? {
// Creates a new client with the backend URL.
final http:Client clientEndpoint = check new ("https://sts.choreo.dev");
json response = check clientEndpoint->post("/oauth2/token",
{
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
"requested_token_type":"urn:ietf:params:oauth:token-type:jwt",
"subject_token":"****"
},
{
"Authorization": "Basic ****"
},
mime:APPLICATION_FORM_URLENCODED
);
io:println(response.toString());
}
This is the recommended way to send the post request with the form URL encoded payload.
Change the Content-type header setting method from addHeader() to setHeader().
The request.setTextPayload(encodedPayload); will set the Content-type as text/plain as the default content type header.
Later request.addHeader("Content-Type","application/x-www-form-urlencoded"); is executed. The addHeader() method will append the new value to the same header in addition to the previously added text/plain. But the setHeader() will replace the previously set header which is the correct way in this scenario.
However better way is to pass the Content-type as the second param of setXXXPayload() method.
request.setTextPayload(encodedPayload, "application/x-www-form-urlencoded");

"Handler crashed with error runtime error: invalid memory address or nil pointer dereference", but POSTMAN is ok! Why this happens?

I work with vue and go for frontend and backend respectively. I send post request to my server and get 403 error code message(notAllowed). But in postman I get the objects and is fine.
Vue and Vuex
My axios post request:
const response = await this.$axios.post(`http://localhost:8000/v1/org/${params.organization}/kkms/${params.kkm}/closeShift`,{
headers : {
'token' : this.state.token.value
}});
I know I should also use other properties like 'Content-Type' and etc in headers, but know it works well with only "token" property in the other requests. I want to know whether problem in backend or frontend?
It seems you have a mistake in the axios request.
You are receiving a 403, that means you are not authorized (or sometimes something else, check the comments in the question and down here ).
As can be found in axios docs, the post request looks like this:
axios.post(url[, data[, config]]).
It accepts the config (so the headers) as THIRD parameter, while you are setting it as second parameter. Add an empty FormData object as second param, and just shift your config to the third param.
const fakeData = new FormData();
const response = await this.$axios.post(`http://localhost:8000/v1/org/${params.organization}/kkms/${params.kkm}/closeShift`,
fakeData,
{
headers : {
'token' : this.state.token.value
}
});

angular5 how to make asyc request?

In my project i made multiple request to server to get data for single page. I want to make all request asyc. Right now until i get the response from first request,the response of second request is not load.
So basically i just want to achive asyc request and response so one request will not wait for other request to finish.
Right now it's like first come first serve fashion.
But i want from multiple request which request get first response should load first.
this is code of my component
constructor(private _dashboardService: DashboardService) {
this.getLineChart();
this.todayPaymentDetails();
this.todayPaymentMethod();
this.rewardCustomers();
this.getAverageBill();
this.getItemByVolumn();
this.getItemBySales();
}
todayPaymentMethod(id=null){
this.paymentMethodsLoader=0;
this._dashboardService.getTodayPaymentMethod(id).subscribe(res =>{
if(null != res.data && '' != res.data){
this.location = res.data.location;
this.payment_methods = res.data.payment_methods;
}
this.paymentMethodsLoader=1;
});
}
this is my service code:
getTodayTotalPayment(id) : Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.get(environment.apiUrl + constants.API_V1 + 'today-total-payment/'+id, options)
.map(res => res.json())
.catch((error: any) => Observable.throw(error.json().error || error));
}
Here shows code for only one request but as shown in constructor i send multiple request at a time.
FIrst it is not a good practise to call function like this in constructor.
For running multiple request or observable together use operators i.e. switchMap etc.
Follow this video link related to event loop in JavaScript this will improve your JavaScript execution , event loop concepts . also explains how asynchronous code executed.
Hope it will help.

How to access Response cookies in angular2?

I'm trying to access this cookies (the response ones):
When I open the request in the chrome debug tools in the network section I can clearly see that the cookies are present, but how can I access those values from my code? I've never worked with cookies before and I don't know what to do to "extract" them... I'm working on a Ionic2 project using Http.
I've read that the allowCredentials: true header has to be sent but that didn't work...
Here's the request/response details:
Here's the service:
public callLogin(service_guid: string, pos_guid: string, login_data: Object) {
return this.http.post(
this.url + service_guid + "/" + pos_guid + "/ack",
login_data,
{withCredentials: true}
)
.map(response => response.headers);
}
And the caller:
this.__posService.callLogin(login_data.service_guid, login_data.pos_guid, {"password": data.password})
.subscribe(
res => {
console.log("Success:");
console.log(res.get("apsession"); // this returns undefined
},
err => {
console.log("Error:");
}
);
When I try to access the cookie from the header it returns undefined. What am I doing wrong here?
The name of the response header you are trying to get is actually Set-Cookie not apsession. So if you did something like res.get("set-cookie") it would return the first header that matched that name. Since you have more than 1, you could do:
let headers: Headers = res.headers;
headers.getAll('set-cookie');
which returns a list of all headers with that name. You could find apsession in there probably.
See:
https://angular.io/docs/ts/latest/api/http/index/Headers-class.html
https://developer.mozilla.org/en-US/docs/Web/API/Response/headers
https://developer.mozilla.org/en-US/docs/Web/API/Headers

How do I inject new request header with json data in proxy request flow?

I am trying to inject a new request header in the proxy request flow using JS policy to be sent to the backend server. When I look at the debug trace, I see that the json data in the request header is distorted.
I am trying to inject some string like
{"scope":"","time_till":2264,"id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM","custom_data":{"c_id":"test_data"}}
But when I look at the trace window I see this
{"scope":"","time_till":2264,id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM,"custom_data":{"c_id":"test_data"}}
what am I doing wrong?
var obj = {"scope":"","time_till":2264,"id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM","custom_data":{"c_id":"test_data"}};
var header_str = JSON.stringify(obj);
context.setVariable('json-header',header_str);
request.headers['x-json-hedar']= header_str;
I tested your code and it seems to work. Here's an example response where I set the header string as a response:
HTTP/1.1 200 OK
User-Agent: curl/7.30.0
Accept: */*
x-json-header: {"scope":"","time_till":2264,"id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM","custom_data":{"c_id":"test_data"}}
Content-Length: 0
It appears this is only an issue with the Apigee debug session / trace tool as the header value was set correctly. Here was the JSON download of the debug session showing this header value:
{
"name": "x-json-header",
"value": "{\"scope\":\"\",\"time_till\":2264,id_1\":\"hUXLXVqpA1J4vA9sayk2UttWNdM,\"custom_data\":{\"c_id\":\"test_data\"}}"
}
You can see that the value passed to the UI for displaying the debug info has the malformed json:
id_1\":\"hUXLXVqpA1J4vA9sayk2UttWNdM,
This does not appear to be a problem with the Apigee debug/trace UI. I see the malformed JSON trickle down to my backend service.
Here is the header I'm trying to send -
{"timeStamp":"2349218349381274","latitude":"34.589","longitude":"-37.343","clientIp":"127.0.0.0","deviceId":"MOBILE_TEST_DEVICE_AGAIN","macAddress":"23:45:345:345","deviceType":"phone","deviceOS":"iOS","deviceModel":"iPhone 5S","connection":"5G","carrier":"Vodafone","refererURL":"http://www.google.com","xforwardedFor":"129.0.0.0","sessionId":"kfkls498327ksdjf","application":"mobile-app","appVersion":"7.6.5","serviceVersion":"1.0","userAgent":"Gecko"}
But Apigee reads the header as below. Note the missing start quotes from some fields.
{"timeStamp":"2349218349381274",latitude":"34.589,longitude":"-37.343,clientIp":"127.0.0.0,deviceId":"MOBILE_TEST_DEVICE_AGAIN,macAddress":"23:45:345:345,deviceType":"phone,deviceOS":"iOS,deviceModel":"iPhone 5S,connection":"5G,carrier":"Vodafone,refererURL":"http://www.google.com,xforwardedFor":"129.0.0.0,sessionId":"kfkls498327ksdjf,application":"mobile-app,appVersion":"7.6.5,serviceVersion":"1.0,"userAgent":"Gecko"}
The header is used in a service callout to a backend service which parses it. And rightly so, I get the below error -
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('l' (code 108)): was expecting double-quote to start field name
at [Source: java.io.StringReader#22549cdc; line: 1, column: 35]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1378)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:599)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:520)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleUnusualFieldName(ReaderBasedJsonParser.java:1275)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._parseFieldName(ReaderBasedJsonParser.java:1170)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:611)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:301)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2796)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1942)
I encounter strange behaviour when adding JSON to a context variable for example like the following:
var header_str = JSON.stringify(obj);
context.setVariable('json-header',header_str);
I appreciate this is an example so you may not have included the full extent of the problem but this normally works (now it is not added to a variable first):
request.headers['x-json-header'] = JSON.stringify(obj);
Code like this also works if you can send the request from JavaScript
var headers = {"Accept": "application/json", "Accept-Language": "en"};
var sessionRequest = new Request(url, 'POST', headers, body);
var exchange = httpClient.send(sessionRequest);
exchange.waitForComplete()
if (exchange.isSuccess()){
var responseObj = exchange.getResponse().content.asJSON;
if (responseObj.error){
request.content += JSON.stringify(responseObj);
}
}
Also, I have had success with using an AssignMessage policy to build a request, followed by a Callout policy to read the stored request and then make that request and store the result in a response object which can then be read by an Extract Variables policy.

Resources