I am building a small Angular frontend support by a REST api in the backend, but I have ran into a very strange problem: doing http.post(url, data, params) results in nothing happening (there's no sign the request ever hits the webserver, in Chrome Developer tools there's absolutely no request logged as opposed to this.http.get() requests, which work fine for URLs on the same server).
export class RestComponent {
constructor ( private http: Http ) {}
sendStuff() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
this.http.post('http://localhost:3021/api/data', {'data': 3}, options)
.catch(this.handleError);
}
}
CORS is enabled on the server
this.http.get on the URL works as expected
there's no evidence in the server logs that the request was ever sent
there's no evidence in Chrome developer tools that the request was sent (no such post request)
logging stuff in the method just before the .post() call shows that everything is as expected (headers, data, etc)
replicating the request in Postman works (identical headers and data)
tried stringyfying the data as well
the error handler does some simple logging, but it's not triggered
I feel quite dumb as it must be something that's fairly obvious yet it escapes me. I've created a simple component which just two methods, one that sends hardcoded data via post and the other that fetches a hardcoded json via get, the second works but the first doesn't.
Would appreciate any pointers.
Thanks!
Essentially you had created just an observable and Observable are lazy in nature. They will get call/emit only when someone has subscribe to them. Hence you have to call subscribe to Observable returned from it to make your code working. Apart from this Everything seems to be perfect.
sendStuff() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post('http://localhost:3021/api/data', {'data': 3}, options)
.catch(this.handleError)
.subscribe(
(data) => console.log(data)
);
}
There's no server code for us to see but make sure that the route is setup to expect content-type application/json because by default a post route will expect post data, depending on what technology you are using for your server.
Also try just doing a relative path maybe: .post('/api/data')
Related
I am new to javascript. I was trying to make an api call.
My code
const options = {
method: 'GET',
headers: {
Authorization: 'Basic dW5kZWZpbmVkOnVuZGVmaW5lZA==',
'content-type': 'application/json',
}
};
fetch(
'https://www.eraktkosh.in/BLDAHIMS/bloodbank/nearbyBB.cnt?hmode=GETNEARBYSTOCKDETAILS&stateCode=21&districtCode=378&bloodGroup=all&bloodComponent=11&lang=0',
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.error(err));
but I encountered with an error saying
Error: Failed to fetch
This api call works perfectly with Hoppscotch
If I try to hit the url right on my url bar, it also works fine.
Any help is strongly appreciated. Thank you from Manoranjan
As other People already mentioned, you can't pass a Body when doing a GET HTTP call, instead you can pass Query Params
Notice this part on the URL
hmode=GETNEARBYSTOCKDETAILS&stateCode=21&districtCode=378&bloodGroup=all&bloodComponent=11&lang=0
Still looking into the code it seems the server have a cors policy, look at this sandbox
See this codesandbox -> https://codesandbox.io/s/peaceful-mcclintock-exuzol?file=/src/index.js
Summary:
GET accept body/payload but it could cause errors, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET
Using the Web API (new headers, new request) for doing the HTTP call
It is better to just avoid sending payloads in GET requests.
Please don't use body with a get request. The GET request is purely meant to collect back data from server, which allows you to sent Queries, not data on the request. Just remove body:'false' or use body:false. The best way is to remove the body from your request so unexpected input is not sent via this GET request.
I understand that there are many similar questions, but I am posting this because I feel it is slightly different.
I am trying to send a GET request to the Slack API using an HTTP request.
Specifically, the code looks like the following.
import useSWR from "swr";
const useSlackSearch = (query: string) => {
const token = process.env.NEXT_PUBLIC_SLACK_API_USER_TOKEN;
const myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer " + token);
const slackURL = `https://slack.com/api/search.messages?query=${query}`;
const fetcher = async (url: string) => {
const response = await fetch(url, {
headers: myHeaders,
}).then((res) => res.json());
return response;
};
const { data, error } = useSWR(slackURL, fetcher, {
revalidateOnFocus: true,
revalidateOnReconnect: true,
});
if (error) {
return console.log(`Failed to load: ${error}`);
} else if (!data) {
return console.log("Loading...");
} else {
console.log(data);
return data;
}
};
export default useSlackSearch;
The environments I'm using are as follows.
Device: MacBook Air
OS: macOS
Browser: Chrome
From: localhost:3000
To: Slack API html page (https://slack.com/api/search.messages)
After reading the MDN articles like below, I understood that
There is such a thing as a simple HTTP request as defined by MDN
If the request you want to send does not correspond to this simple request, the browser will send a preflight request
In the response to that preflight request, there is a header called Access-Control-Allow-Headers.
Only headers set to the value of this Access-Control-Allow-Headers header can be used as headers in the main request after preflighting.
In this case, I tried to use the Authorization header, but it was trapped by the above restriction.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
That's all I understand.
However, on the official Slack API page for the method in question, it says to specify the token in the Authorization header, so I'm having trouble.
I also don't understand how to specify the Access-Control-Request-Headers in the preflight header, as described in another questioner's thread. The reason is that the only thing that communicates to the Slack API is the browser in this case, and the only relevant source is JavaScript (React / Next.js to be exact)!
After that, I found preflight response from Slack API as follows;
access-control-allow-headers: slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, x-b3-sampled, x-b3-flags
As I thought, I understand that Authorization is not allowed because it is not included as a value. So the question is how to solve it.
Furthermore, I found out later that the preflight request from the browser properly declared that it wanted to use Authorization as an actual request header. However, the preflight response did not contain the value.
Following CBroe's advice, I was able to contact the Slack help center directly, so I asked this problem. What I found out as a result is that HTTP requests from browsers are not supported as of the end of February 2022. Of course, they have received quite a lot of requests regarding this, so they hope to address it at some point.
This time, the browser sent Access-Control-Request-Headers:Authorization in the preflight request. But the Slack API server side did not allow the Authorization header in the request from the browser. Therefore, Authorization was not set in the Access-Control-Allow-Headers in the preflight response from the Slack API side.
As a result, the response from the Slack API side returned Invalid Auth, even though Authorization was added as a header when making an actual request from the browser.
Through this error, I gained a deeper understanding of HTTP requests such as CORS and preflighting, but since it is not explicitly written on the official Slack website, I left it here.
What is Preflight: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
What is Access-Control-Allow-Header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
What is CORS simple request: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
I could not get the Authorization header to work either. However, Slack provided this example for adding token authentication to the Post body following the deprecation of the query parameters method.
This worked for me to make Web API calls to Slack from the browser (for testing) so that Slack would read the token for authentication. Note, according to Slack's best practices for security, user and bot tokens should be stored with care and not used in client-side Javascript:
try {
const res = await fetch("https://slack.com/api/conversations.list", {
method: "POST",
body: `token=${TOKEN}`, // body data type must match "Content-Type" header
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}).catch((error) => {
console.log(error);
});
if (!res.ok) {
throw new Error(`Server error ${res.status}`);
} else {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.log(error);
}
using token in request body instead of Authorization header worked for me.
axios({
method: 'post',
url: 'https://slack.com/api/chat.postMessage',
data: `text=Hi&channel=D048GGYTJUK&token=${process.env.TOKEN}`
})
I'm building PWA with Angular 5. And having problem with duplicated execution of PUT requests. I'm also running POST and GET requests but this bug appears only with PUT.
This is the method
put(url: string, data: string): Observable<any> {
console.log('put');
const options = {
headers: new HttpHeaders({
'Content-Type': 'text/xml'
})
};
return this.http
.put(url, data, options).map(resp => {
console.log('put_output');
return resp;
});
}
It makes two requests when this method runs only once.
Network tab screenshot:
Console output screenshot:
I've tried to run simple XMLHttpRequest and it was perfect: one request, one response.
The first request is a Preflighted Request, this behavior is OK, and some developers call it "Handshake with server".
From DOCS:
"preflighted" requests first send an HTTP request by the OPTIONS
method to the resource on the other domain, in order to determine
whether the actual request is safe to send. Cross-site requests are
preflighted like this since they may have implications to user data.
You can also check the issue here.
I are trying to fetch data from our API. The API has enabled CORS support and returns the below response to the OPTIONS request:
Access-Control-Request-Headers:content-type
Access-Control-Allow-Origin:*
The API doesn't allow 'Content-type' anything other than 'application/json'.
Using this limitation, I am trying to use the fetch method of React-Native to get the data.
Method 1 (no-cors):
{
method: 'POST',
mode: "no-cors",
headers: {
'content-type': 'application/json'
}
With this method, the browser automatically sends the content-type as 'text/plain'. I assume this is because CORS allow just one of the three headers by default. However, since the server doesn't support this content-type, it returns an error back for unsupported content type.
Method 2 (with cors or with nothing):
{
method: 'POST',
mode: "cors", // or without this line
redirect: 'follow',
headers: {
'content-type': 'application/json'
}
}
...
.then(response => console.log(response))
In this scenario, using Chrome's F12 network tool, I can see the server returning data : the first request to the server is a fetch for OPTIONS. To this, the server replies back with an empty object along with the above headers set. The next call is the actual POST API call, to which the server responds back with a proper JSON response containing some data. However, the response which is getting on the console via my code is {}. I assume this is because the react's fetch API is returning back the response of the OPTIONS call instead of the actual POST call.
Is there any way to ignore the response of the OPTIONS request and get the then method to process the response of the subsequent request?
The immediate problem you’re hitting is, your code as currently written expects the response to be JSON but the response is actually a Promise that you need to handle to get the JSON.
So you need to instead do something like this:
fetch("https://example.com")
.then(response => response.json())
.then(jsondata => console.log(jsondata))
Using angular v1.3.1 i got a singular the following problem trying to implement a facade for making http request to a REST + JSON interface in the backend of the web app.
I got something like this in the code:
findSomething(value: number): ng.IPromise<api.DrugIndication[]> {
const getParams = { 'param' : 'value' };
const config:ng.IRequestShortcutConfig = {
headers: {
"Content-Type" : "application/json"
},
data: getParams
}
return this.$http.get(url,config);
}
And when the times comes to invoke it, i got an 400 Bad Request (btw: Great name for a band!) because the backend (made with Play for Scala) rejects the request inmediately. So making an inspection in the request i see that no data is being send in the body of the request/message.
So how i can send some data in the body of and HTTP Get request using angular "$http.get"?
Additional info: This doesn't happen if i the make request using the curl command from an ubuntu shell. So probably is an problem between Chrome and angular.js
If you inspect the network tab in chrome development tools you will see that this is a pre-flight OPTIONS request (Cross-Origin Resource Sharing (CORS)).
You have two ways to solve this.
Client side (this requires that your server does not require the application/json value)
GET, POST, HEAD methods only
Only browser set headers plus these
Content-Type only with:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Server side
Set something like this as a middleware on your server framework:
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
w.Header().Set("Access-Control-Max-Age", "86400") // firefox: max 24h, chrome 10min
return
}
For your specific framework this should work
Using config.data will send the data in the request body, use
config.params = getParams
This is from the documentation :
params – {Object.} – Map of strings or objects which will be serialized with the paramSerializer and appended as GET parameters