I've been trying to post a paste to Pastebin in Node.js, but it appears that I'm doing it wrong.
I'm getting a Bad API request, invalid api_option, however I'm clearly setting the api_option to paste like the documentation asks for.
var http = require('http');
var qs = require('qs');
var query = qs.stringify({
api_option: 'paste',
api_dev_key: 'xxxxxxxxxxxx',
api_paste_code: 'Awesome paste content',
api_paste_name: 'Awesome paste name',
api_paste_private: 1,
api_paste_expire_date: '1D'
});
var req = http.request({
host: 'pastebin.com',
port: 80,
path: '/api/api_post.php',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Content-Length': query.length
}
}, function(res) {
var data = '';
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
console.log(data);
});
});
req.write(query);
req.end();
console.log(query) confirms that the string is well encoded and that api_option is there and set to paste.
Now, I've been searching forever on possible causes. I also tried setting the encoding on the write req.write(query, 'utf8') because the Pastebin API mentions that the POST must be UTF-8 encoded. I rewrote the thing over and over and re-consulted the Node HTTP documentation many times.
I'm pretty sure I completely missed something here, because I don't see how this could fail. Does anyone have an idea of what I have done wrong?
What you're creating isn't a properly-formed multipart/form-data request; it looks more like an application/x-www-form-urlencoded request. From what I can tell about pastebin's API (I've never actually used it) the latter is what you really want, so try changing the Content-Type to it.
It does not answer directly your question but maybe it could help...
Have you try to use the request module ?
Your example would be much easier to read and you might find the problem...
mikeal/request
Related
I am creating a Firefox extension which posts some data to a database.
I made all parts in a modular fashion and am now combining everything piece by piece.
As such I know that my code to POST data to the database works.
Now here is the part that stumps me :
When I then add this code to my firefox extension
I get the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3003/timed_shot_create. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 400.
Now ofcourse CORS was nothing new and to be expected when dealing with Cross Origin Resource Sharing, it is even in the name.
But the reason why I am here is because this pertains only to the response of the POST request. The request itself is fine and allowed with the following piece of config in the server:
app.use(
cors({
//todo change to proper origin when live
origin: "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d",
method: ["GET", "POST"],
})
);
Which was later changed to:
app.use(
cors({
origin: "*",
method: ["GET", "POST"],
})
);
And then simplified even more to:
app.use(cors())
This is in Nodejs btw using cors middleware.
But none of this seems to work when it is used inside a firefox extension, as a local client page works as intended but as soon as I add this to a firefox extension I get a CORS error specifically pertaining to the reponse message.
The client side post (in the background script of the extension) is:
async function postTimedShot(post_options) {
const response = await fetch(post_endpoint, post_options);
//console.log(response);
const json_response = await response.json();
console.log(json_response);
}
let post_options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(response_data),
};
postTimedShot(post_options);
And the api looks like this:
app.post("/timed_shot_create", (req, res) => {
console.log("Received POST request");
const data = req.body;
console.log(data);
const timeStamp = data.time_stamp;
//TODO add screenshot and Description text maybe??
//const lastName = data.last_name
const queryString =
"INSERT INTO " + timed_shots_database + " (time_stamp) VALUES (?)";
getConnection().query(queryString, [timeStamp], (err, results, fields) => {
if (err) {
console.log("Failed to insert new user: " + err);
res.sendStatus(500);
return;
}
//Todo change this message when adding more data in body
//res.header("Access-Control-Allow-Origin", "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d");
res.json({
status: "Success!!!",
time_stamp: timeStamp,
});
console.log("Inserted a new user with id: ", results.insertId);
});
});
Furthermore, this extension is only for personal use and will work with a local server under my complete control so complications due to security or cloud usage that people want to mention are appreciated but not necessary (I think, I am a bit of novice).
I will be happy to clarify anything that is unclear, or change this post if necessary, but I think it is a unique question as far as I could see on SO. Additionally if I need to provide more of the codebase I will.
I will also update this post if I find out more about this problem.
Thank you for reading :3.
After reading about this post https://stackoverflow.com/a/53025865/5055963
on SO I found out that it had to do with the permissions in the manifest of the extension.
Adding this line: "://.localhost/*".
Solved the issue for me.
When my Telegram bot sends sendMessage to Telegram server it gets the error message:
{"ok":false,"error_code":400,"description":"Bad Request: message text is empty"}
The problem appeared this morning, before that my bot worked a whole year without errors. GetUpdates command works well as before. I use GET HTTP method to send commads:
https://api.telegram.org/bot<MyToken>/sendMessage
with UTF-8-encoded data attached:
{"chat_id":123456789,"text":"any text"}
Has anyone encountered this?
If the issue still persists, try to modify your curl request. For me adding header
'Content-Type: application/json' and -d '{"chat_id":12309832,"text":"any text"}' fixed issue
Another way to send a message by emulating a form :
curl -s -X POST https://api.telegram.org/bot{apitoken}/sendMessage \
-F chat_id='-1234567890' -F text='test message'
Well, i wrote wrapper on C language to communicate via SSL with telegram bot api. SO now I can clearly answer questions about telegram API spec.
Problem number one
First of all if we are talking about raw queries we need to remember about specifications.
By default HTTP/HTTPS post requests should consists of:
<METHOD>[space]<PATH with only valid chars> <\r\n>
<HOST valid regexed\r\n>
<Content-type valid regexed><\r\n>
<Content-Length with length of your POST body data><\r\n>
<\r\n before body>
<body>
So, i tried to send raw queries with out Content-Length and i had error same as yours. That's the first problem.
Problem number two
By default if you trying to send non valid request with sendMessage method - telegram bot api will response with error same as yours. So, yeah, that's pretty tricky error to debug...
If you trying to send raw query, be sure that your JSON data is serialized nicely and there is no errors like shielding.
Summarizing
Request:
POST /bot<token>/sendMessage HTTP/1.1
Host: api.telegram.org:443
Connection: close
Content-Type: application/json
Content-Length: 36
{"chat_id":<integer>, "text":"test \\lol"}
Second backslash if shielding.
Code on C
sprintf(reqeustCtx.request,
"POST /bot%s/%s HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s\r\n", bot_token, bot_method,
reqeustCtx.res_addr, strlen(body), body);
BIO_puts(bio, reqeustCtx.request);
BIO_flush(bio);
memset(reqeustCtx.response, '\0', BUFFSIZE);
read_bytes = BIO_read(bio, reqeustCtx.response, BUFFSIZE);
if (read_bytes <= 0) {
printf("No response");
exit(-1);
}
cert_free(cert_store, ssl_ctx, ca_cert_bio);
// free memory //
reqeustCtx.method(reqeustCtx.res_addr, reqeustCtx.request,
reqeustCtx.current_work_dir, reqeustCtx.current_cert);
/* json response, need to parse */
return reqeustCtx.response;
I got this error too.
I used sendMessage() method only with "low-level" Node https:
const https = require('https');
const data = JSON.stringify({
chat_id: config.telegram.chatId,
text: 'some ASCII text'),
});
const options = {
hostname: 'api.telegram.org',
port: 443,
path: `/bot${config.telegram.botToken}/sendMessage`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = https.request(options, (res) => {
let chunks = [];
res.on('data', chunk => chunks.push(chunk));
res.on('end', () => {
const resBody = Buffer.concat(chunks).toString('utf8');
if (res.statusCode === 200) {
console.log(`Message sent`);
} else {
console.error(`${res.statusCode} ${res.statusMessage} ${res.headers['content-type']}
${resBody}`)
}
});
});
req.on('error', (error) => {
reject(error)
});
req.write(data);
req.end();
And for ASCII text it was ok, however for some non-ASCII text I got:
const data = JSON.stringify({
chat_id: config.telegram.chatId,
text: 'Привет Мир!'),
});
Error:
400 Bad Request application/json
{"ok":false,"error_code":400,"description":"Bad Request: message text is empty"}
In my case content length was calculated with invalid length 'Content-Length': data.length (invalid for Telegram?...), so I comment out this header and now it works for UTF-8!
headers: {
'Content-Type': 'application/json',
//'Content-Length': data.length
}
In my case, I was using curl_setopt($this->curl, CURLOPT_POSTFIELDS, json_encode($fields)); to post this json via sendMessage method:
{
"chat_id":000000000,
"text":"Choose one of the following options: ",
"reply_to_message_id":292,
"reply_markup":{
"keyboard":[
[
"Enable",
"Disable"
]
]
}
}
The problem was that when passing fields to the curl_setopt method, I was encoding the whole php array so I solved it by just encoding the reply_markup array which was a part of my json.
Try to put "Message" object with chat_id & text to HttpEntity in your restTemplate service, like below:
public MessageDto sendMessage(Message message) {
return restTemeplate.exchange(
"https://api.telegram.org/bot{token}/sendMessage",
HttpMethod.POST,
new HttpEntity<>(message, HttpHeaders.EMPTY),
MessageDto.class
).getBody();
}
I'm using superagent and jasmine-ajax in my testing environment (karma with jasmine adapter).
I noticed an issue pertaining to case-sensitivity on the response headers when trying to mock responses that superagent will then handle.
Testing code:
it('should parse the response as json', function() {
var response = '{ "foo" : "bar" }';
superagent.get('/some/url', function(
expect(response.body).toEqual({ foo: "bar" });
});
jasmine.Ajax.requests.mostRecent().response({
status: 200,
// uncomment following line to make this test pass
// responseHeaders: { "content-type" : "application/json" },
responseText: response
});
});
In superagent.js line ~695 has:
this.header['content-type'] = this.xhr.getResponseHeader('content-type');
In mock-ajax.js line ~175 has
this.responseHeaders = response.responseHeaders ||
{"Content-type": response.contentType || "application/json" };
So, obviously within each respective library, there is a discrepancy with casing, but, according to spec, all the research I've done says that this field is case-insensitive. I thought that it might be an issue with PhantomJS, but I just tried using Chrome as well, but the same issue is present.
Any insight would be appreciated.
I need to send custom headers to my wcf oData Service but with the following function the headers dont get modified.
entities.onReady(function () {
entities.prepareRequest = function(r) {
r[0].headers['APIKey'] = 'ABC';
};
entities.DataServiceClient.toArray(function (cli) {
cli.forEach(function (c) {
console.log(c.Name)
});
});
});
headers are not affected. any clue?
thanks!
It seems that the marked answer is incorrect. I was suffering from a similar issue, but got it working without changing datajs.
My issue was that I was doing a cross domain (CORS) request, but didn't explicitly allow the headers. After I added the correct CORS header to the webservice, it worked.
EDIT
On second thought, it seems like there is still something broken in JayData for MERGE requests.
This is NOT CORS and has nothing to do with it!
see JayData oData request with custom headers - ROUND 2
the bellow "hack" works, but the above question should take this problem to a new level.
----------
Old answer
Nevermind I found a solution.
It seems like prepareRequest is broken in JayData 1.3.2 (ODataProvider).
As a hack, I added an extraHeaders object in the providerConfiguration (oDataProvider.js):
this.providerConfiguration = $data.typeSystem.extend({
//Leave content unchanged and add the following:
extraHeaders: {}
}, cfg);
then at line 865 modify requestData like this:
var requestData = [
{
requestUri: this.providerConfiguration.oDataServiceHost + sql.queryText,
method: sql.method,
data: sql.postData,
headers: _.extend({
MaxDataServiceVersion: this.providerConfiguration.maxDataServiceVersion
},this.providerConfiguration.extraHeaders)
},
NOTE: Iam using lodash for conveniance, any js extend should do the trick.
then you just create your client like this:
var entities = new Entities.MyEntities({
name: 'oData',
oDataServiceHost: 'http://myhost.com/DataService.svc',
maxDataServiceVersion: "2.0",
//enableJSONP: true,
extraHeaders: {apikey:'f05d1c1e-b1b9-5a2d-2f44-da811bd50bd5', Accept:'application/json;odata=verbose'}
}
);
I'm trying to use CORS to have a script do an Ajax request to geonames.
My script calls this web service method: http://www.geonames.org/export/web-services.html#findNearby
If you check the response headers of the sample call, they include:
Access-Control-Allow-Origin: *
When I try this with mootools (version 1.4.5 just downloaded):
var urlGeonames = "http://api.geonames.org/findNearbyPlaceName";
var req = new Request({
method: 'get',
url: urlGeonames,
data: {
'lat': '89.18',
'lng': '-0.37',
'username': 'myusername',
'radius': '5'
}
}).send();
then I get an error that says :
XMLHttpRequest cannot load
http://api.geonames.org/findNearbyPlaceName?lat=89.18&lng=-0.37&username=myusername&radius=5.
Origin http://127.0.0.1 is not allowed by Access-Control-Allow-Origin.</pre>
On the other hand, when I try old style Ajax code like this:
invocation = new XMLHttpRequest();
if(invocation)
{
invocation.open('GET', urlFlickr, true);
invocation.onreadystatechange = handler;
invocation.send();
}
then it works and I get the XML response in the XHR responseXML.
I found this post A CORS POST request works from plain javascript, but why not with jQuery? that is similar. But here I'm not dealing with my server so I can only work on the javascript side.
Has anyone worked with CORS and mootools and can help on this issue ?
Thanks so much
JM
Hey man check out mootools more JSONP this will solve your problem:
http://mootools.net/docs/more/Request/Request.JSONP
Also it looks like your forgetting to ask for it in JSON format from geonames.org
Try something like:
var myJSONP = new Request.JSONP({
url: 'http://api.geonames.org/findNearbyPlaceNameJSON',
data: {
'lat': '89.18',
'lng': '-0.37',
'username': 'myusername'
},
onRequest: function(url){
// a script tag is created with a src attribute equal to url
},
onComplete: function(data){
// the request was completed.
console.log(data);
}
}).send();
Hope this helps!
The first answer on this other thread:
MooTools CORS request vs native Javascript
Might help.
Basically, the X-Requested-With header is automatically sent by the Mootools with the request, but the server either has to be configured to accept that header or you can remove it using
delete foo.headers['X-Requested-With'];
Before calling
foo.send();
To allow it by the server, you can add this to the .htaccess file of your script that gives back the JSON data:
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"
So yours would look like:
var myJSON = new Request({
url: 'http://api.geonames.org/findNearbyPlaceNameJSON',
data: {
'lat': '89.18',
'lng': '-0.37',
'username': 'myusername'
},
onRequest: function(url){
// a script tag is created with a src attribute equal to url
},
onComplete: function(data){
// the request was completed.
console.log(data);
}
});
delete myJSON.headers['X-Requested-With'];
myJSON.send();