There is a nice post how to create a CORS Fairing.
The given solutions worked fine as long as there was no the preflight request (PUT, DELETE).
The partial solution I've found is given by Mike Mannakee
It's slightly modify:
async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) {
response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
response.set_header(Header::new("Access-Control-Allow-Methods", "*"));
response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
if request.method() == Method::Options {
println!("Option => {}", request.uri());
response.set_status(Status::NoContent);
}
}
Unfortunately, DELETE method still doesn't work
--- put ---
OPTIONS /api/code_data/m4test/breakpoint:
>> No matching routes for OPTIONS /api/code_data/m4test/breakpoint.
>> No 404 catcher registered. Using Rocket default.
Option => /api/code_data/m4test/breakpoint
>> Response succeeded.
PUT /api/code_data/m4test/breakpoint application/json:
>> Matched: (add_breakpoint_handler) PUT /api/code_data/<game_name>/breakpoint
application/json
Add breakpoint 2
>> Outcome: Success
>> Response succeeded.
--- delete ----
OPTIONS /api/code_data/m4test/breakpoint:
>> No matching routes for OPTIONS /api/code_data/m4test/breakpoint.
>> No 404 catcher registered. Using Rocket default.
Option => /api/code_data/m4test/breakpoint
>> Response succeeded.
DELETE /api/code_data/m4test/breakpoint text/plain:
>> No matching routes for DELETE /api/code_data/m4test/breakpoint text/plain.
>> No 404 catcher registered. Using Rocket default.
>> Response succeeded.
rocekt_cors didn't work for me, too.
The preflight req is visible in FF. Not sure how can it be shown in Chrome.
Please could you share you solution if you had a similar issue?
Thunder client, Postman, curl worked wo any issue.
Update:
The issue was "the content type negotiation" - "content-type" was commented out in the first fetch. Everything works as expected:
if (!breakpoint) {
// delete
wasm?.update_breakpoints({}, [address]);
// TODO: handle errors
await fetch(`http://localhost:8000/api/code_data/${currentGame}/breakpoint`, {
method: 'delete',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({ address }),
});
} else {
// add breakpoint
wasm?.update_breakpoints({ [address]: breakpoint }, []);
// TODO: handle errors
await fetch(`http://localhost:8000/api/code_data/${currentGame}/breakpoint`, {
method: 'put',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({ address, ...breakpoint }),
});
}
Related
I want to post multiple logs to DataDog from a JS function, using a single HTTP request. Looking at the v2 docs for DataDog's 'send logs' POST endpoint, it sounds like this is possible:
For a single log request, the API ... For a multi-logs request, the API ...
But it's not clear to me from the docs how to actually send a 'multi-logs' request. I've tried the following:
const dataDogEndpoint = 'https://http-intake.logs.datadoghq.com/api/v2/logs';
const body = {
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: ['My first production log.', 'My second production log.'],
service: 'my-service'
};
const response = await fetch(dataDogEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': apiKey
},
body: JSON.stringify(body)
});
Perhaps unsurprisingly, this appears in DataDog as a single log with the following content:
[My first production log., My second production log.]
How can I achieve this?
Got it - this can be achieved by adding multiple log objects to the body like so:
const dataDogEndpoint = 'https://http-intake.logs.datadoghq.com/api/v2/logs';
const body = [{
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: 'My first production log.',
service: 'my-service'
},{
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: 'My second production log.',
service: 'my-service'
}];
const response = await fetch(dataDogEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': apiKey
},
body: JSON.stringify(body)
});
(You'll probably want a loop instead of instantiating each log object separately.)
I deployed a firebase HTTP cloud function and am experiencing this (unexpected) behavior:
when I call the function (using POST) from a browser environment with fetch(), the function gets triggered twice, one time without any data sent in the body, and another time as I would expect it. In the frontend (chrome network tab) I can only see 1 request, the successfull one.
this does only happen with POST requests
this does only happen when the request is sending headers
Is this normal behavior that I dont understand or a potential bug?
my minimal cloud function
exports.run = functions.https.onRequest(async (req, res) => {
// ALLOW CORS FOR POST REQUEST:
// => https://stackoverflow.com/a/38259193
res.set('Access-Control-Allow-Origin', '*');
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
return res.status(200).send({
status: "ok",
body: req.body,
query: req.query,
}).end();
});
calling from frontend
// example data (not a real one)
const url = "https://us-central1-myproject.cloudfunctions.net/test";
const postData = { x: 1, y: 2 };
// GET request => ✅ works as expected
fetch(url);
// POST request without headers => ✅ works as expected
fetch(url, {
method: 'POST',
body: JSON.stringify(postData),
});
// POST request with headers => ❌ 2 requests get triggered
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(postData),
});
This behavior is happening because of the CORS preflight request:
A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers.
...
A preflight request is automatically issued by a browser, and in normal cases, front-end developers don't need to craft such requests themselves. It appears when a request is qualified as "to be preflighted" and omitted for simple requests.
As pointed in this other question:
As long as you’re adding a Content-Type': 'application/json' header to the request, the browser is going to automatically on its own do a CORS preflight OPTIONS request before trying the request from your code.
Therefore, this is a normal behavior and is not a problem of Cloud Functions for Firebase.
In order to not have the two requests, you can change the header request as suggested by this answer:
// example data (not a real one)
const url = "https://us-central1-myproject.cloudfunctions.net/test";
const postData = { x: 1, y: 2 };
// POST request with different header => ✅ only one request is triggered
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: JSON.stringify(postData),
}).then(data => console.log(data));
Unable to share image content through share endpoint, image asset is uploaded through assets API but my request to share API which is copied directly from the example here https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/share-api?context=linkedin/compliance/context#share-content returns an error, invalid parameters in the request body [/Headers] see below details.
Request Headers:
{Authorization: Bearer ***
X-Restli-Protocol-Version: 2.0.0
}
Request Body
{"content":{"contentEntities":[{"entity":"urn:li:digitalmediaAsset:C5622AQEEn3mmqzCb5w"}],"title":"Great Result","landingPageUrl":"https://google.com.au","shareMediaCategory":"IMAGE"},"distribution":{"linkedInDistributionTarget":{}},"owner":"urn:li:person:zzR_UbXjsG","subject":"Great Result","text":{"text":"Great result, couldn't have gone better #realestate"}}
Scopes:
scope=r_emailaddress w_member_social w_organization_social r_basicprofile rw_company_admin rw_organization_admin
Error:
{"serviceErrorCode":100,"message":"Unpermitted fields present in REQUEST_BODY: Data Processing Exception while processing fields [/Headers]","status":403}
It looks like the error message has to do with the headers. Your request body is JSON, but you don't have a Content-Type header set, so this could be the problem:
Content-Type: application/json
Generally, you need a Content-Length header to be sent along with that, but most of the time the client you are using to send the request handles setting that one.
I'm not sure how you're making the request, but here is a fetch() example in JavaScript (make sure you put the correct auth token in the Authorization header):
const url = 'https://api.linkedin.com/v2/shares';
const requestBody = {
"content": {
"contentEntities": [
{
"entity": "urn:li:digitalmediaAsset:C5622AQEEn3mmqzCb5w"
}
],
"title": "Great Result",
"landingPageUrl": "https://google.com.au",
"shareMediaCategory": "IMAGE"
},
"distribution": {
"linkedInDistributionTarget": {}
},
"owner": "urn:li:person:zzR_UbXjsG",
"subject": "Great Result",
"text": {
"text": "Great result, couldn't have gone better #realestate"
}
};
async function makeRequest(url, requestBody) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ***',
'X-Restli-Protocol-Version': '2.0.0'
},
body: JSON.stringify(requestBody) // body data type must match "Content-Type" header
});
return await response.json(); // parses JSON response into native JavaScript objects
}
// make the actual request
makeRequest(url, requestBody);
I’m calling a service using a token
Failed to load resource: the server responded with a status of 401 (Unauthorized)
Http failure response for http://localhost:65291/api/post: 401 Unauthorized
The same call works in Postman with Headers;
Content-Type: application/json
Authorization: Bearer token
The function in ionic is
getPosts() {
var header = new HttpHeaders({ "Content-Type": "application/json" });
header.append("Authorization", "Bearer " + this.token);
console.log("Bearer " + this.token);
return new Promise(resolve => {
console.log(this.apiUrl + '/post');
this.http.get(this.apiUrl + '/post', { headers: header}).subscribe((data: Post[]) => {
resolve(data);
}, err => {
console.log(err);
});
});
}
Added a log for the token to be sure that is adding it to the header correctly (the token is fine).
The apiUrl variable has value http://localhost:65291/api.
What is wrong here? Cors is enabled… Postman works ok…
Thanks
I think you definitely have client side problem (since its 401 and also you mention Postman works ok).
I had similar issues when I tried to append headers in the same fashion you did so I would suggest trying this (to eliminate this problem):
getPosts() {
// try forming headers object in one go:
let token = "Bearer "+this.token
let headers = new HttpHeaders({
"Content-Type": "application/json",
"Authorization": token
});
// now here I am not sure why you do promise wrapping this way, but then I would suggest:
return this.http.get(this.apiUrl + '/post', { headers: headers })
.toPromise()
.then((data: Post[]) => { // Success
console.log(data);
resolve(data);
}, (err) => {
console.log(err);
});
}
If the problem is still there - please share which version of Angular and Http module you are using?
Also check out this issue here: How to correctly set Http Request Header in Angular 2
And specifically this answer if you are on Angular 4.3+:
How to correctly set Http Request Header in Angular 2
After a while I found the problem,
header.append("Authorization", "Bearer " + this.token); is wrong. It worked using
let headers = new HttpHeaders({"Authorization: " + "Bearer " + this.token})
Setting multiple headers:
this.http
.post('api/items/add', body, {
headers: new HttpHeaders({
'Authorization': 'my-auth-token',
'x-header': 'x-value'
})
}).subscribe()
I had a similar problem, it works on postman and cors enabled but in the app doesn't work, my problem was i have / at the end of the URL in the API security config, and i was making the request without /, i just remove it from request URL,
also you can add /* in security config or put / in your app, the URL must be the same.
(maybe you have solved your issue and it was different issue but this is a possibe solution)
my axios code:
const instance = axios.create({
baseURL: process.env.BASE_API,
timeout: 5000,
withCredentials: true,
headers: {
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
})
function get (url, getData) {
return instance.get(url, {
params: getData
})
}
function post (url, postData) {
return instance.post(url, qs.stringify(postData))
}
function put (url, putData) {
return instance.put(url, qs.stringify(putData))
}
export default {
get: get,
post: post,
put: put
}
Post request with content-type': 'application/x-www-form-urlencoded; charset=UTF-8 is useful
However, when using PUT, the request header does not have a content-type': 'application/x-www-form-urlencoded; charset=UTF-8
Causes the put request to become an options
It's not so clear from your question what exactly you are trying to ask. I'll assume you want your PUT request to actually send a PUT request instead of just an OPTIONS request. I'm also assuming that you are making requests to an API that you control.
I had the same problem (i.e. I was only seeing OPTIONS requests when I tried to make PUT calls) and I discovered that in my API I did not have the PUT options enabled in my CORS settings. I'm using rails so all I had to do is add :put to my cors middleware:
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :put, :options]
end
end
I figured this out based on this answer