AFCompoundResponseSerializer JSON issue - objective-c

I'm using AFNetworking's latest version in a project that connects to an API that returns both text responses and JSON responses so I use AFCompoundResponseSerializer to handle both response.
Request that return a JSON file are given to me as a NSString of the JSON response instead of an NSDictionnary that is normaly returned with AFJsonResponseSerializer, it looks like the AFCompoundResponseSerializer takes the response as plain text and doesn't send it to the AFJsonResponseSerializer
My code fore the CompoundSerializer is as follow:
sharedSessionManager = [[self alloc] initWithBaseURL:[NSURL URLWithString:baseURL]];
sharedSessionManager.responseSerializer=[AFCompoundResponseSerializer compoundSerializerWithResponseSerializers:#[[AFJSONResponseSerializer serializer], [AFHTTPResponseSerializer serializer]]];

I found out why this happened:
The server returned JSON as text/html so the serializer sended it directly to AFHTTPResponseSerializer which returned a string instead of parsing the JSON.
To fix this, just add text/html to the JSON serializer's acceptableContentTypes

Related

Webhook call failed. Error: Failed to parse webhook JSON response: Expect message object but got: [Chinese letters]

I'm building my own WebhookClient for dialog flow. My code is the following (using Azure Functions, similar to Firebase Functions):
module.exports = async function(context, req) {
const agent = new WebhookClient({ request: context.req, response: context.res });
function welcome(agent) {
agent.add(`Welcome to my agent!!`);
}
let intentMap = new Map();
intentMap.set("Look up person", welcome);
agent.handleRequest(intentMap);
}
I tested the query and the response payload looks like this:
{
"fulfillmentText": "Welcome to my agent!!",
"outputContexts": []
}
And the headers in the response look like this:
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Tue, 11 Dec 2018 18:16:06 GMT
But when I test my bot in dialog flow, it returns the following:
Webhook call failed. Error: Failed to parse webhook JSON response:
Expect message object but got:
"笀ഀ਀  ∀昀甀氀昀椀氀氀洀攀渀琀吀攀砀琀∀㨀 ∀圀攀氀挀漀洀攀 琀漀 洀礀 愀最攀渀琀℀℀∀Ⰰഀ਀  ∀漀甀琀瀀甀琀䌀漀渀琀攀砀琀猀∀㨀 嬀崀ഀ਀紀".
There's Chinese symbols!? Here's a video of me testing it out in DialogFlow: https://imgur.com/yzcj0Kw
I know this should be a comment (as it isn't really an answer), but it's fairly verbose and I didn't want it to get lost in the noise.
I have the same problem using WebAPI on a local machine (using ngrok to tunnel back to Kestrel). A friend of mine has working code (he's hosting in AWS rather than Azure), so I started examining the differences between our responses. I've notice the following:
This occurs with Azure Functions and WebAPI (so it's not that)
The JSON payloads are identical (so it's not that)
Working payload isn't chunked
Working payload doesn't have a content type
As an experiment, I added this code to Startup.cs, in the Configure method:
app.Use(async (context, next) =>
{
var original = context.Response.Body;
var memory = new MemoryStream();
context.Response.Body = memory;
await next();
memory.Seek(0, SeekOrigin.Begin);
if (!context.Response.Headers.ContentLength.HasValue)
{
context.Response.Headers.ContentLength = memory.Length;
context.Response.ContentType = null;
}
await memory.CopyToAsync(original);
});
This code disables response chunking, which is now causing a new and slightly more interesting error for me in the google console:
*Webhook call failed. Error: Failed to parse webhook JSON response: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 94 path $.\u0000\\"\u0000f\u0000u\u0000l\u0000f\u0000i\u0000l\u0000l\u0000m\u0000e\u0000n\u0000t\u0000M\u0000e\u0000s\u0000s\u0000a\u0000g\u0000e\u0000s\u0000\\"\u0000.\
I thought this could be encoding at first, so I stashed my JSON as a string and used the various Encoding classes to convert between them, to no avail.
I fired up Postman and called my endpoint (using the same payload as Google) and I can see the whole response payload correctly - it's almost as if Google's end is terminating the stream part-way through reading...
Hopefully, this additional information will help us figure out what's going on!
Update
After some more digging and various server/lambda configs, I spotted this post here: https://github.com/googleapis/google-cloud-dotnet/issues/2258
It turns out that json.net IS the culprit! I guess it's something to do with the formatters on the way out of the pipeline. In order to prove this, I added this hard-coded response to my POST controller and it worked! :)
return new ContentResult()
{
Content = "{\"fulfillmentText\": null,\"fulfillmentMessages\": [],\"source\": null,\"payload\": {\"google\": {\"expectUserResponse\": false,\"userStorage\": null,\"richResponse\": {\"items\": [{\"simpleResponse\": {\"textToSpeech\": \"Why hello there\",\"ssml\": null,\"displayText\": \"Why hello there\"}}],\"suggestions\": null,\"linkOutSuggestion\": null}}}}",
ContentType = "application/json",
StatusCode = 200
};
Despite the HTTP header saying the charset is utf-8, that is definitely using the utf-16le character set, and then the receiving side is treating them as utf-16be. Given you're running on Azure, it sounds like there is some configuration you need to make in Azure Functions to represent the output as UTF-8 instead of using UTF-16 strings.

API Connect 5 - Error attempting to read the urlopen response data

I'm trying to create a REST API from a SOAP Service using IBM API Connect 5. I have followed all the steps described in this guide (https://www.ibm.com/support/knowledgecenter/en/SSFS6T/com.ibm.apic.apionprem.doc/tutorial_apionprem_expose_SOAP.html).
So, after dragging the web service block from palette, ensuring the correctness of endpoint and publishing the API, I have tried to call the API from the browser. Unfortunately, the API return the following message:
<errorResponse>
<httpCode>500</httpCode>
<httpMessage>Internal Server Error</httpMessage>
<moreInformation>Error attempting to read the urlopen response
data</moreInformation>
</errorResponse>
To testing purpose, I have logged the request and I have tried the request on SOAPUI. The service return the response correctly.
What is the problem?
In my case, the problem was in the backend charset (Content-Type: text/xml;charset=iso-8859-1).
For example, backend returns text/xml in German (or French). Api Connect cannot process character ü. It needs Content-Type: text/xml;charset=UTF-8.
I had a similar issue, in my case was the accept. if you have an Invoke and the content-type or the accept, is not matching the one of the request, or the response that you got, APIC is getting mad.
Please, check if the formats to send (contentType) and receive (accept) are the same of that your API expected. In my case the error occurs because the API returns a String and my default code is configured to receive a JSON body.
//define a JSON-PLAIN TEXT protocol
private HttpEntity<String> httpEntityWithBody(Object objToParse){
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + "xxx token xxx");
headers.set("Accept", MediaType.TEXT_PLAIN_VALUE);
headers.setContentType(MediaType.APPLICATION_JSON);
Gson gson = new GsonBuilder().create();
String json = gson.toJson(objToParse);
HttpEntity<String> httpEntity = new HttpEntity<String>(json, headers);
return httpEntity;
}
//calling the API to APIC...
ParameterizedTypeReference<String> responseType = new
ParameterizedTypeReference<String>(){};
ResponseEntity<String> result =
rest.exchange(builder.buildAndExpand(urlParams).toUri(), HttpMethod.PUT, httpEntityWithBody(myDTO), responseType);
String statusCode = result.getStatusCodeValue();
String message = result.getBody();

Objective-C - Base64 string to base64Binary (XML)

I'm developing an app on iOS requesting a web service with SOAP, and I have an issue with the datatype xsd:base64Binary (XML).
I build my SOAP envelope according to the expected fields from the web service. When the types are xsd:string or xsd:integer or any other simple type, I have no problem.
But when I try to add an xsd:base64Binary type to the SOAP envelope, the web service cannot receive the data correctly; it seems to be an encoding issue but I can't figure it out.
For example, the envelope looks like :
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema- to instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<hereTheMethod xmlns="http://heretheaddress/">
<aBase64>/9j/4AAQSkZJRgAB...
...RRQAUUUUAf/Z</aBase64>
<aBool>false</aBool>
<anInt>89</anInt>
<aDouble>0.0</aDouble>
<aString>Hello</aString>
</hereTheMethod>
</soap12:Body>
</soap12:Envelope>
Then the web service reads "false", "89", "0.0" or "Hello" without any problem. But with base64, I have something like "����JFIF��XExifMM*�i&..." as an encoding problem.
In Objective-C, I proceed like :
NSMutableString *envelopeText = [NSMutableString stringWithFormat:#"(header)\n"
"<aBase64>%#</aBase64>\n"
"(footer)", base64String];
// Some code...
NSData *envelope = [envelopeText dataUsingEncoding:NSUTF8StringEncoding];
// I launch the connection.
Lastly, when I build the base64 string, I take care to encode it in UTF-8 like :
NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Notice that the app also exists for Android (Java), and works with the same web service correctly.
Thanks for your help !
PS : Sorry for my English :/
try use CDATA for Base64 string like this:
<aBase64><![CDATA[%#]]></aBase64>\n

RKObjectPaginator did not send GET request to server

I have a RKObjectPaginator and have set the necessary parameters. But my server did not receive any query.
RKURL *patternURL = [[[RKObjectManager sharedManager] baseURL] URLByAppendingResourcePath:ResourcePathPattern];
RKObjectPaginator *paginator = [[RKObjectPaginator alloc] initWithPatternURL:patternURL mappingProvider:[self paginationMappingProvider]];
paginator.delegate = self;
[paginator loadPage:0];
My log console reads:
2012-09-12 20:56:36.975 keytech search ios[1692:c07] Will load page: 0
2012-09-12 20:58:06.613 keytech search ios[1692:c07] D restkit.network:RKRequest.m:436 Sending asynchronous GET request to URL 'http://-MyServerIP-:8080/keytech/GetNextSearchResults?pageSize=25&pageNumber=0.
2012-09-12 20:58:06.613 keytech search ios[1692:c07] T restkit.network:RKRequest.m:402 Prepared GET URLRequest '<NSMutableURLRequest >http://-MyServerIP-:8080/keytech/GetNextSearchResults?pageSize=25&pageNumber=0>'. HTTP Headers: {
"Content-Length" = 0;
}. HTTP Body: .
But no request is send to the server.
Have I done everything right? If I post the URL in my browser, the server responds well. It seems that this query is not send.
I have no clue why this request is not send.
Is there a 'best-practise' example how to use RKObjectPaginator?
You might not be able to load page 0.
try [paginator loadPage:1];
I am also looking for a sample myself on how to do this. In your case I believe that you are missing the PageCount and ObjectCount properties. It seems to me that you have to set that up manually.
BTW: did you ever resolve it?

Restkit loading gzipped json

I'm using RestKit to load a gzipped JSON with RKRequest:
RKRequest* request = [[RKClient sharedClient] requestWithResourcePath:urlString delegate:self];
[request send];
but I receive a status 406. When using AsiHttpRequest everything works, the response gets unzipped and I can work with the JSON. When I turn off gzip on server the RKRequest works.
What is wrong? I found no way to tell RKRequest, that the response will be zipped. Any ideas?
EDIT:
It is strange. Sometimes I get
Headers: {
Connection = "Keep-Alive";
"Content-Length" = 14;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Fri, 16 Mar 2012 13:44:16 GMT";
"Keep-Alive" = "timeout=2, max=500";
Server = Apache;
"X-Powered-By" = "Servlet/2.5 JSP/2.1";
}
and sometimes I get application/gzip which is handled correct. My problem is why I get "Content-Type" = "text/html; charset=UTF-8"; sometimes.
And the same request opened in Safari results in a gzip-response always.
Can you post what's in your headers using an HTTP Proxy (like Charles)?
You may need to modify your "request headers" in the post call.
Make sure your firewall is able to accept POST calls. This might be an https issue.
EDIT:
You may need to configure your server to always return the response as a GZIP and DEFLATE based on the extension type. This is based on here (http://betterexplained.com/articles/how-to-optimize-your-site-with-gzip-compression/).
Example:
# compress json format in .htaccess (for apache servers):
AddOutputFilterByType DEFLATE application/json
You can find the 'mod_deflate' documentation here (http://httpd.apache.org/docs/2.0/mod/mod_deflate.html)
If you can post the outgoing headers, that would also be useful, as they should include:
Accept-Encoding: gzip, deflate
Similar issues
https://groups.google.com/forum/?fromgroups#!topic/restkit/Xo84PH1l5kM
Weird "406 not acceptable" error
https://serverfault.com/questions/183843/content-length-not-sent-when-gzip-compression-enabled-in-apache
EDIT:
Make sure you also do this:
[[RKClient sharedClient] setValue:#"gzip" forHTTPHeaderField:#"Accept-Encoding"];
or this
[[RKClient sharedClient] setValue:#"gzip, deflate" forHTTPHeaderField:#"Accept-Encoding"];
This should set the value of your header to accept "gzip" for encoding the response. I noticed these github issues:
https://github.com/RestKit/RestKit/pull/540
https://github.com/RestKit/RestKit/issues/511