I'm working with a slightly unconventional API that is expecting a JSON body with a GET request and I have no control over this. Unfortunately, every time I attempt to make the request, it seems to completely disappear and never make it to the API. I originally wrote the request using a standard URLSession and then switched to try Alamofire in an attempt to fix it but ended with the same result. My request looks like this:
Alamofire.request("http://192.168.1.1:8000/connect/", method: .get, parameters: ["test": "test"], encoding: JSONEncoding.default)
.responseJSON { response in
let body = response.request?.httpBody
guard response.result.isSuccess else {
onCompletion(nil)
return
}
onCompletion(response.result.value as! [String : Any]?)
}
This exact code works for a different request where there is no JSON in the body, but seemingly the moment I add it, it just times out. This has already been discussed on the alamofire github repo (https://github.com/Alamofire/Alamofire/issues/1819) but the final comment with what should be working code isn't really any different to mine, so doesn't provide any help, nor do the other linked issues.
Printing the request with debugPrint gives me this curl command
$ curl -i \
-H "Content-Type: application/json" \
-d "{\"test\":\"test\"}" \
"http://192.168.1.1:8000/connect/"
Which is missing the -X GET flag, but when I add that in, the request works as expected and the server responds, so I know the API itself is working and is happy processing the JSON in the body, so I'm at a loss as to what's going on.
I've installed Timberjack to attempt to trace things, which didn't give me any more info at all, just what I already knew
Request: GET http://192.168.1.1:8000/connect/
Headers: [
Content-Type : application/json
Content-Length : 24
]
Although I'm not sure if it's supposed to be showing me the body as well which it isn't?
In both cases (URLSession and Alamofire) the request gives the following output which I don't see at any other time:
2017-01-22 23:31:09.797453 my-app[3755:1349066] [] nw_endpoint_flow_service_writes [2 192.168.1.1:8000 ready socket-flow (satisfied)] Write request has 4294967295 frame count, 0 byte count
2017-01-22 23:32:04.484182 my-app[3755:1349066] [] __tcp_connection_write_eof_block_invoke Write close callback received error: [89] Operation canceled
Anyone have any ideas on what's going on as I'm completely at a loss at this point.
Update
I've done some more digging. If I change the endpoint to https://httpbin.org/get then the request goes through just fine and I get a response. Whilst this kind of suggests the API server is refusing to process the request, it's still working with the cURL command so that can't really be the issue.
I also forgot to mention (although not sure it should make a difference) that the API I'm trying to communicate with is connected via an ad-hoc wifi. Other requests to it work just fine though so I can definitely communicate with it.
Update 2
So I've been able to switch the server to using POST instead of GET and unsurprisingly it now works, however I would still love to know of a solution to the original problem
URLSession and CFHTTPMessage cannot send a message body for a GET request. They send the content length for the body, but do not send the body itself. This results in a timeout.
In order to resolve this issue I've used libcurl to handle the GET requests which have a message body to my project. I use URLSession everywhere else. When you add a body to a request using libcurl it changes the request to a POST, but that can be changed back to a GET after setting the body and before submitting the request.
Related
I've to use a C++ library for sending data to a REST-Webservice of our company.
I start with Boost and Beast and with the example given here under Code::Blocks in a Ubuntu 16.04 enviroment.
The documentation doesn't helped me in following problem:
My code is, more or less, equal to the example and I can compile and send a GET-request to my test webservice successfully.
But how can I set data inside the request (req) from this definition:
:
beast::http::request<beast::http::string_body> req;
req.method("GET");
req.target("/");
:
I tried to use some req.body.???, but code completition doesn't give me a hint about functionality (btw. don't work). I know that req.method must be changed to "POST" to send data.
Google doesn't show new example about this, only the above code is found as a example.
Someone with a hint to a code example or using about the Beast (roar). Or should I use websockets? Or only boost::asio like answered here?
Thanks in advance and excuse my bad english.
Small addition to Eliott Paris's answer:
Correct syntax for setting body is
req.body() = "name=foo";
You should add
req.prepare_payload();
after setting the body to set body size in HTTP headers.
To send data with your request you'll need to fill the body and specify the content type.
beast::http::request<beast::http::string_body> req;
req.method(beast::http::verb::post);
req.target("/");
If you want to send "key=value" as a "x-www-form-urlencoded" pair:
req.set(beast::http::field::content_type, "application/x-www-form-urlencoded");
req.body() = "name=foo";
Or raw data:
req.set(beast::http::field::content_type, "text/plain");
req.body() = "Some raw data";
I am trying to invoke a POST web service via Postman and I am getting the following error.
Error while sending request: Failed to execute setRequestHeader on
XMLHttpRequest: Value is not a valid ByteString.
Request Headers
X-PW-AccessToken:{{api_token}}
X-PW-Application:developer_api
X-PW-UserEmail:{{api_email}}
Content-Type:application/json
Request Body
{
"page_size": 25
}
Can anyone tell me why I am getting this error, and how can I get rid of this?
I think Http protocol's header can only post ByteString (what is ByteString? I think it is ASCII).
So if you have other char, for example, 汉字. if you put '汉字' add to Http Header the error 'Value is not a valid ByteString' happen!
Solove: You can use the encodeURI function to encode the String in the client, and then, You can use URLdecode.decode()(java) to decode the header information in the server.
This is a follow up of this question. At first I thought the issue was resolved after checking out the example from the Qt wiki (I use the same code without a single change). However it appears that it's the URL that is the culprit. I tried using the links provided in this answer to test my http GET request. Using the Http Requester (Firefox addon for Http requests (GET, POST etc.)) and curl shows no issues with this link^:
$~: curl --request GET --url "http://httpbin.org/ip"
For some reason Qt gets stuck and the readyRead()/finished() signals are never emitted.
As a result the request gets cancelled after some time due to socket timeout...For something that is really small and opened by Firefox in less than a second.
I'm far from an expert when it comes to Http stuff. I'd like to know why this behaviour occurs in Qt while there is no sign of it when working with other tools.
EDIT: I've also tested the problematic URLs using Python and its urllib
import urllib.request
res = urllib.request.urlopen("http://httpbin.org/ip").read().decode("utf-8")
import xml.etree.ElementTree as ET
doc = ET.fromstring(res)
and it works just fine. Clearly there is something with Qt going on and/or me missing something when using it.
EDIT2: I've also tried another test service for HTTP requests - https://postman-echo.com. With curl there is no problem:
$~: curl --request GET --url "https://postman-echo.com/get?foo1=bar1&foo2=bar2"
For my surprise though there is no problem with Qt either! The only thing that I see here as a huge difference is that postman-echo.com uses HTTPS while the other URLs I've tried were HTTP. I exclude the https://www.qt.io which was the default URL in the Qt example and worked just fine (though it didn't have any parameters).
Try executing that in an event loop. Here is something similar to what I do in a non-gui application:
QUrl req_url = QUrl(href);
QNetworkRequest request(req_url);
//request.setRawHeader("Content-Type", "application/json;utf8");
//q_nam is QNetworkAccessManager created earlier
QNetworkReply *reply = q_nam->get(request);
QEventLoop event_loop;
connect(q_nam, SIGNAL(finished(QNetworkReply * ) ), &event_loop, SLOT(quit() ) );
event_loop.exec(); // blocks stack until "finished()" has been called
event_loop.processEvents(QEventLoop::ExcludeUserInputEvents, 500 );//what events to processed and for how long
event_loop.exit();
QNetworkReply::NetworkError er = reply->error();
// ....continue handling
I forgot to mention that I'm behind. Frankly I feel rather stupid for missing this and also not checking through the guest network at work (which circumvents the stupid proxy). A colleague of mine tried using HTTPS instead of HTTP (which is the original link). The HTTPS is also something that the proxy just lets go through without any issues. And it worked.
However a more neutral solution is (as my colleagues found out) to use QNetworkProxyFactory::setUseSystemConfiguration(true) which takes the proxy configuration that I have system-wide.
the bash command I used to connect the bot is: curl -ik -X POST 'https://graph.facebook.com/v2.6/me/messages?access_token=#AccessToken'
My error message is:
{"error":{"message":"(#100) The parameter recipient is
required","type":"OAuthException","code":100,"fbtrace_id":"EFqWAGq2ABs"}}
Do anyone how to solve it ?
Just in case anyone missed this, I encountered this issue when I accidentally use the wrong content type - I was using application/x-www-form-urlencoded instead of application/json
So my advise overall is,
Check if you are indeed passing the parameter
Double check the characters and encoding
Make sure to use the correct endpoint
and Make sure to use the correct content type when posting the JSON Request.
You need to send the recipient id param. Try:
curl -X POST -H "Content-Type: application/json" -d '{ "recipient":{"id":"YOUR RECIPIENT ID" }, "message":{ "text":"hello from bot" }}' "https://graph.facebook.com/v2.6/me/messages?access_token=YOUR_ACCESSTOKEN"
Best regards.
There is another reason for this error message: when you send incorrect characters (like a -tab-) Facebook return this error as well so check your return text on special chars.
Please use the "thread_settings" endpoint "https://graph.facebook.com/v2.6/me/thread_settings" as your API endpoint.
You are using the messages endpoint.
It comes down to the logic of your bot. I got this error as well just recently and it took me days to debug it. The problem for me was I called the callSendAPI(messageData) method outside of the function that compiled the messageData object.
Obviously, passing messageData outside of the function that compiles it sends an empty object instead of the compiled one. Thus the error message (#100) The parameter recipient is required. Simply because the empty object doesn't have any receipientId defined.
Please check your code's logic to ensure you didn't do the same mistake as I. Hope this helps :) Happy programming.
The endpoint is wrong. Instead of https://graph.facebook.com/v2.6/me/messages?access_token=#AccessToken, use this endpoint
https://graph.facebook.com/v2.6/me/messenger_profile?access_token=<PAGE_ACCESS_TOKEN>
This happens when we do not read the documentation., the info is right here https://developers.facebook.com/docs/messenger-platform/discovery/welcome-screen#,
right under the "Setting the Get Started Button Postback".
I got similar error some time back. Try using Postman. I tried the same request and replaced the user id and the page access token. It works fine.
Click on the Import button on the top and paste your curl request under raw. Then try running the call. If you get the same error, go to the body and modify it. Make sure you put this in the body part of the Postman request. Replace the recipient id with yours.
{
"recipient":
{
"id":"123456789"
},
"message":
{
"text":"hello, world!"
}
}
This is the full cURL call : Change Recipient ID and Page Access Token
curl -X POST -H "Content-Type: application/json" -d '{ "recipient":{"id":"1234567" }, "message":{ "text":"hello from bot" }}' "https://graph.facebook.com/v2.6/me/messages?access_token=PASTETHETOKENHERE"
This issue may also occur when you have an error in your code (syntax or logic error). In my case, I had this part in my code in webhook.php (which is my registered callback page in Facebook)
$message = $input['entry'][0]['messaging'][0]['message']['text'];
"message":{
"text":"Sorry, we currently do not have an article related to "'.$message.'"."
}
By the time I registered https://domain.com/webhook.php as callback, it wouldn't receive any $message yet so it causes an error and wouldn't accept my callback url.
Check your code and make sure you echo only the challenge.
$challenge = $_REQUEST['hub_challenge'];
$verify_token = $_REQUEST['hub_verify_token'];
if ($verify_token === 'verify_token') {
echo $challenge;
}
(This is the first time I've done this actually.)
<mx:HTTPService id="post_update" method="POST" result="{Dumper.info('bye')}"/>
The result handler above is just for debugging purposes, but its never hit, even though what I'm uploading via POST...
post_update.url = getPath(parentDocument.url)+"update";
post_update.send(new_sel);
...is received and handled successfully by my Django view:
def wc_post(request) :
request.session['wc'] = request.POST
return http.HttpResponse("<ok/>", mimetype="text/xml")
As far as what I'm sending back from Django, I'm following the guidelines here:
Sending Images From Flex to a Server
I just don't want it to generate an error on the Flex side considering Django is actually receiving and processing the data. Any help appreciated. Can't remember the text of the error in Flex at the moment.
UPDATE: new_sel (what I'm posting from Flex) is just a Flex Object, with various text fields.
UPDATE: various error messages from event.message (in fault handler):
faultCode = "Server.Error.Request"
faultString = "HTTP request error"; DSStatusCode = 500; errorID = 2032; type = "ioError"
This is more grasping at straws than answers, but do I have to send a particular type of header back from Django- the default sent by Django includes a 200 success status code, and the response I was sending of "<ok/>" with mime type of "text/xml" was following the example exactly that I provided from that other source.
And also the url I'm sending the POST to is localhost:8000/wr_view1/wr_webcube/update, and I previously successfully did a GET to localhost:8000/wr_view1/wr_webcube/webcube.xml, and despite the .xml extension in the case of GET, it was still being handled by Django (and without errors in Flex). In the case of this POST, once again, the data is actually succesfully sent and handled by Django, but Flex is returning Error 2032, which I found out can mean numerous different things including cross domain issues, but don't see how that's the case here.
Just had to return HttpResponse("ok") Didn't like it being sent as xml for some reason. So much ado about nothing I guess.