How to get HTTP status code in HTTPService fault handler - actionscript-3

I am calling a server method through HTTPService from client side. The server is a RestFul web service and it might respond with one of many HTTP error codes (say, 400 for one error, 404 for another and 409 for yet another). I have been trying to find out the way to determine what was the exact error code sent by the server. I have walked teh entire object tree for the FaultEvent populated in my fault handler, but no where does it tell me the error code. Is this missing functionality in Flex?
My code looks like this:
The HTTP Service declaration:
<mx:HTTPService id="myServerCall" url="myService" method="GET"
resultFormat="e4x" result="myServerCallCallBack(event)" fault="faultHandler(event)">
<mx:request>
<action>myServerCall</action>
<docId>{m_sDocId}</docId>
</mx:request>
</mx:HTTPService>
My fault handler code is like so:
private function faultHandler(event : FaultEvent):void
{
Alert.show(event.statusCode.toString() + " / " + event.fault.message.toString());
}

I might be missing something here, but:
event.statusCode
gives me the status code of the HTTP response.
So I can successfully do something like this in my fault handler function:
public function handleFault(faultEvent:FaultEvent):void
{
if (faultEvent.statusCode == 401)
{
Alert.show("Your session is no longer valid.", "", Alert.OK, this, loginFunc);
}
else
{
Alert.show("Failed with error code: " + faultEvent.statusCode as String);
}
}

Looks like you are out of luck: http://fantastic.wordpress.com/2007/12/26/flex-is-not-friendly-to-rest/
You may have to use ExternalInterface to get this handled in JS and then communicated to Flex.

The Flash Player needs help from the browser to be able to access the HTTP status code; therefore, this is not available on all platforms. For me, it failed with Flash Player 10.3.183.11 and Firefox 3.6.26, but worked with IE 8 on Windows 7.
The Adobe help for the FaultEvent.statusCode property hints at this, but unfortunately doesn't go into details:
this property provides access to the HTTP response status code (if available), otherwise the value is 0
So, if you absolutely need the status code, bad luck; if it's just to generate a better or friendlier error message for some frequent error conditions, it may be sufficient.

as3httpclient as posted by Ross is friendly to Rest, and provides you with the HTTP status code, as long as you're developing for AIR and not a browser-based app.
I could not get as3httpclient to work from the browser, even when making requests to the same origin. There's documentation stating you need to set up a socket policy file server to get this to work. Not scalable for our uses so I setup a Proxy web service on the same host running the flex app.
I use HTTPService to make the call to the proxy web service, which forwards the request to the destination, and the proxy web service returns the http status code and message body back to the HTTPService in xml.

Try using this instead of HTTPService:
http://code.google.com/p/as3httpclient/

Related

Exception: '<' is an invalid start of a value

I have a Blazor Webassembly project with a controller method as follows:
[HttpGet]
public async Task<List<string>> GetStatesForProfile()
{
IConfigurationSection statesSection = configuration.GetSection("SiteSettings:States");
var sections = statesSection.GetChildren();
var states = statesSection.GetChildren().Select(s => s.Key).ToList<string>();
return states;
}
The razor page calls this method:
private async Task<bool> GetStatesModel()
{
try
{
States = await http.GetJsonAsync<List<string>>("api/account/getstatesforprofile");
...
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}, Inner: {ex.InnerException.Message}");
}
I get this Exception:
Exception: '<' is an invalid start of a value.
I read these values from appsettings.json file, And there is no '<' in values.
{
"SiteSettings": {
"States": {
"New York": ["NYC"],
"California": ["Los Angeles", "San Francisco"]
}
}
Also I put a breakpoint in the controller method and it doesn't hit.
What is this error? Is it from parsing json? and how to resolve this?
I had a very similar problem.
In the end it turned out that my browser had cached the HTML error page (I guess I had some problems with the code when I first tried it). And no matter how I tried fixing the code I still only got the error from cache. Clearing my cache also cleared the problem.
It happens when you're trying to access an API that doesn't exist. You have to check your API project connectionstring under AppSettings and make sure it's correct and running. If it's a Blazor project, you can set it as your default project, execute and see if you get a json response.
Most probably the response you are receiving is html instead of actual JSON format for the endpoint you are requesting. Please check that.
An as HTML usually starts with <html> tag, the JSON validator fails on the very first character.
You should also clear any cache, that might be interfering with the returned data. (this has helped people resolve this same issue)
I know this is an old question, but it's one of the top results when Googling the error.
I've just spent more time than I care to admit to tracking down this error. I had a straightforward Blazor hosted app, basically unchanged from the template. It worked just fine when run locally, but when published to my web host API calls failed. I finally figured out that the problem was that I was running the publish from the Client project. When I changed to the Server project it worked properly.
Hopefully my long frustration and slight stupidity will save someone else making a similar mistake.
Seems like your api is not not accessible and its returning error HTML page by default.
You can try below solution:-
I think you are using httpclient to get data to blazor application.
If you have separate projects in solution for blazor and web api,
currently your startup application may set to run blazor project only.
Change startup projects to multiple (blazor and web api app) and give httpClient url in startup of blazor application, as webApi application url, that may solve your issue.
This error indicates a mismatch of the project targeting framework version and installed runtime on the machine. So make sure that the target framework for your project matches an installed runtime - this could be verified by multiple means; one of them is to check out the Individual Components tab of the Visual Studio Installer and lookup the target version.
E.g., there is the TargetFramework attribute in the proj file:
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
Then launch the Visual Studio Installer, click Modify, and visit the Individual Components tab:
Install the missing runtime (.NET 5 Runtime in this case) and you're good to go.
I got the same error. Red herring. use your browser or postman to check your api endpoint is returning the json data and not some HTML. In my case my "api/companytypes" had a typo.
private CompanyType[] companytypesarray;
private List<CompanyType> CompanyTypeList;
private List<CompanyType> CompanyTypeList2;
public async Task<bool> LoadCompanyTypes()
{
//this works
CompanyTypeList = await Http.GetFromJsonAsync<List<CompanyType>>("api/companytype");
//this also works reading the json into an array first
companytypesarray = await Http.GetFromJsonAsync<CompanyType[]>("api/companytype");
CompanyTypeList2 = companytypesarray.ToList();
return true;
}
I know this is an old question, but I had the same problem. It took some searching, but I realized that the return data was in XML instead of JSON.
I'm assuming your "http" variable is of type HttpClient, so here's what I found worked for me.
By setting the "Accept" header to allow only JSON, you avoid a miscommunication between your app and the remote server.
http.DefaultRequestHeaders.Add("Accept", "application/json");
States = await http.GetJsonAsync<List<string>>("api/account/getstatesforprofile");
I had the same issue when passing in an empty string to a controller method. Creating a second controller method that doesn't accept any input variables, and just passing an empty string to the first method helped to fix my problem.
[HttpGet]
[ActionName("GetStuff")]
public async Task<IEnumerable<MyModel>> GetStuff()
{
return await GetStuff("");
}
[HttpGet("{search}")]
[ActionName("GetStuff")]
public async Task<IEnumerable<MyModel>> GetStuff(string search)
{
...
}
Versions of package
Try to update your packages to old or new version. In my case, system.net.http.json is updated from 6.0 to 5.0
Likely you are using an Asp.NetCore hosted WASM application. By default the client's App.razor has something similar to:
<CascadingAuthenticationState>
<Router AppAssembly="#typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView DefaultLayout="#typeof(MainLayout)"
RouteData="#routeData">
<NotAuthorized>
<RedirectToLogin />
</NotAuthorized>
<Authorizing>
<Loading Caption="Authorizing..."></Loading>
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="#typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
Herein lies the problem. Since the Client and Server share the same base address, when the application cannot find "api/account/getstatesforprofile" it gives you the client's "Sorry, there's nothing at the address" page. Which is of course HTML.
I have not found the solution to this issue, but I am working on it and will reply once I find an issue.
I was having the same problem,
"JsonReaderException: '<' is an invalid start of a value."
In my case the url for the REST service was wrong.
I was using the URL from the client project. Then I looked at the Swagger screen,
https://localhost:44322/swagger/index.html
and noticed the right URL should start with "44322"...
Corrected, worked.
In my case, I had a comma (,) written mistakenly at the beginning of the appsettings.json file ...
Just check your file and verify
///////
my error details
//////
System.FormatException HResult=0x80131537 Message=Could not parse the JSON file.
Source=Microsoft.Extensions.Configuration.Json StackTrace: at line 16 This exception was originally thrown at this call stack: [External Code] Inner Exception 1: JsonReaderException: ',' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
////
For me, most of the time it is the #lauri-peltonen answer above. However, now and again, depending on who wrote the controller I have found that this will work in Swagger but not when you call it via the client (at least in this Blazor project we are on.)
[HttpGet]
[Route("prog-map-formulations")]
public async Task<List<GetProgramMapFormulationsResult>> GetProgramMapFormulations(int formulationId)
{
...
}
It sends the request as:
api/formulation-performance-program-map/analytical-assoc-values?formulationId=1
And I get results in Swagger but failes with the '<' OP error.
When I change ONLY the route to:
[HttpGet]
[Route("prog-map-formulations/{formulationId:int}")]
public async Task<List<GetProgramMapFormulationsResult>> GetProgramMapFormulations(int formulationId)
{
...
}
It sends the request as:
api/formulation-performance-program-map/analytical-assoc-values/1
And this works in both Swagger as well as from the Client side in Blazor.
Of course, once updated, I did have to clear the cache!
If you delete "obj" folder in your directory then clean the solution and rebbuild it the exception will be resolved
In all these, there is two things that was my issue and realized, first off was that Route[("api/controller")] instead of Route[("api/[controller]")], that is missing square brackets. In the second exercise I was doing, with the first experience in mind, was from the name of the database. The database had a dot in the name (Stock.Inventory). When I change the database name to StockInventory it worked. The second one I am not so sure but it worked for me.

JAX-WS adds namespace in Signature of token

I am accessing a third party web service using JAX-WS generated client (Java) code.
A call to a service that initiates a client session returns a Token in the response which, a.o., contains a Signature. The Token is required in subsequent calls to other services for authentication purposes.
I learned from using SoapUI that the WS/Endpoint requires the Token to be used as-is... meaning everything works fine when I literally copy the Token (which is one big line) from the initial response to whatever request I like to make next.
Now I am doing the same in my JAX-WS client. I retrieved a Token (I copied it from the response which I captured with Fiddler) and I tested it succesfully in a subsequent call using SoapUI.
However, when performing a subsequent call to a service using the JAX-WS client, the Signature part in the Token is changed. It should look like:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">...</Signature>
But (when capturing the request with Fiddler) it now looks like:
<Signature:Signature xmlns:Signature="http://www.w3.org/2000/09/xmldsig#" xmlns="http://www.w3.org/2000/09/xmldsig#">...</Signature:Signature>
Apparently this is not acceptable according to the WS/Endpoint so now I'd like to know:
Why is the Token marshalled back this way?
More importantly, how can I prevent my client from doing that?
Thanks in advance!
Have you tested it? It should work nevertheless. The original signature used the defautl namespace (...xmldigsig) the JAXB version uses the same namespace but explicit says that the Signature element belongs to that namespae (Signature:Signature). The effect is the same, both xml express that Signature is in the http://www.w3.org/2000/09/xmldsig# namespace
You can customize the jaxby output with #XMLSchema on the package info, #XMLType on the class or inside the element.
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
By the help of #Zielu I was able to solve this by altering package-info.java (in the package of the generated files) like so:
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://namespaceofthirdparty-asingeneratedversionof package-info.java"
, xmlns = {
#javax.xml.bind.annotation.XmlNs(namespaceURI = "http://www.w3.org/2000/09/xmldsig#", prefix = "")
}
, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) package com.where.generated.files.are;

why DeferredResult ends on setResult() on trying to use SSE

i am trying to implement a Server Sent Events (SSE) webpage which is powered by Spring. My test code does the following:
Browser uses EventSource(url) to connect to server. Spring accepts the request with the following controller code:
#RequestMapping(value="myurl", method = RequestMethod.GET, produces = "text/event-stream")
#ResponseBody
public DeferredResult<String> subscribe() throws Exception {
final DeferredResult<String> deferredResult = new DeferredResult<>();
resultList.add(deferredResult);
deferredResult.onCompletion(() -> {
logTimer.info("deferedResult "+deferredResult+" completion");
resultList.remove(deferredResult);
});
return deferredResult;
}
So mainly it puts the DeferredResult in a List and register a completion callback so that i can remove this thing from the List in case of completion.
Now i have a timer method, that will periodically output current timestamp to all registered "browser" via their DeferredResults.
#Scheduled(fixedRate=10000)
public void processQueues() {
Date d = new Date();
log.info("outputting to "+ LoginController.resultList.size()+ " connections");
LoginController.resultList.forEach(deferredResult -> deferredResult.setResult("data: "+d.getTime()+"\n\n"));
}
The data is sent to the browser and the following client code works:
var source = new EventSource('/myurl');
source.addEventListener('message', function (e) {
console.log(e.data);
$("#content").append(e.data).append("<br>");
});
Now the problem:
The completion callback on the DeferredResult is called on every setResult() call in the timer thread. So for some reason the connection is closed after the setResult() call. SSE in the browser reconnects as per spec and then same thing again. So on client side i have a polling behavior, but i want an kept open request where i can push data on the same DeferredResult over and over again.
Do i miss something here? Is DeferredResult not capable of sending multiple results? i put in a 10 seconds delay in the timer thread to see if the request only terminates after setResult(). So in the browser the request is kept open until the timer pushes the data but then its closed.
Thanks for any hint on that. One more note: I added async-supported to all filters/servlets in tomcat.
Indeed DeferredResult can be set only once (notice that setResult returns a boolean). It completes processing with the full range of Spring MVC processing options, i.e. meaning that all you know about what happens during a Spring MVC request remains more or less the same, except for the asynchronously produced return value.
What you need for SSE is something more focused, i.e. write each value to the response using an HttpMessageConverter. I've created a ticket for that https://jira.spring.io/browse/SPR-12212.
Note that Spring's SockJS support does have an SSE transport which takes care of a few extras such as cross-domain requests with cookies (important for IE). It's also used on top of a WebSocket API and WebSocket-style messaging (even if WebSocket is not available on either the client or the server side) which fully abstracts the details of HTTP long polling.
As a workaround you can also write directly to the Servlet response using an HttpMessageConverter.

How to fix cross-site origin policy for server and web-site

I'm using Dropwizard, which I'm hosting, along with a website, on the google cloud (GCE). This means that there are 2 locations currently active:
Some.IP.Address - UI
Some.IP.Address:8080 - Dropwizard server
When the UI tries to call anything from my dropwizard server, I get cross-site origin errors, which is understandable. However, this is posing a problem for me. How do I fix this? It would be great if I could somehow spoof the addresses so that I don't have to fully qualify the resource in the UI.
What I'm looking to do is this:
$.get('/provider/upload/display_information')
Or, if I have to fully qualify
$.get('http://Some.IP.Address:8080/provider/upload/display_information')
I tried setting Origin Filters in Dropwizard per this google groups thread (https://groups.google.com/forum/#!topic/dropwizard-user/ybDOTOxjlLI), but it doesn't seem to work.
In index.html that is served by the server at http://Some.IP.Address you might have a jQuery script that look as follows.
$.get('http://Some.IP.Address:8080/provider/upload/display_information', data, callback);
Of course your browser will not allow accessing http://Some.IP.Address:8080 due to the Same-Origin-Policy (SOP). The protocol (http, https) and the host as well as the port have to be the same.
To achieve Cross-Origin Resource Sharing (CORS) on Dropwizard, you have to add a CrossOriginFilter to the servlet environment. This filter will add some Access-Control-Headers to every response the server is sending. In the run method of your Dropwizard application write:
import org.eclipse.jetty.servlets.CrossOriginFilter;
public class SomeApplication extends Application<SomeConfiguration> {
#Override
public void run(TodoConfiguration config, Environment environment) throws Exception {
FilterRegistration.Dynamic filter = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
filter.setInitParameter("allowedOrigins", "http://Some.IP.Address"); // allowed origins comma separated
filter.setInitParameter("allowedHeaders", "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filter.setInitParameter("allowedMethods", "GET,PUT,POST,DELETE,OPTIONS");
filter.setInitParameter("preflightMaxAge", "5184000"); // 2 months
filter.setInitParameter("allowCredentials", "true");
// ...
}
// ...
}
This solution works for Dropwizard 0.7.0 and can be found on https://groups.google.com/d/msg/dropwizard-user/xl5dc_i8V24/gbspHyl4y5QJ.
This filter will add some Access-Control-Headers to every response. Have a look on http://www.eclipse.org/jetty/documentation/current/cross-origin-filter.html for a detailed description of the initialisation parameters of the CrossOriginFilter.

Trying to send an HTTP request over sockets

I'm having trouble sending out a simple HTTP request using Actionscript 3's Socket() object. My onConnect listener is below:
function sConnect(e:Event):void {
trace('connected');
s.writeUTFBytes('GET /outernet/client/rss/reddit-feeds HTTP/1.1\r\n');
s.writeUTFBytes('Host: 208.43.71.50:8080\r\n');
s.writeUTFBytes('Connection: Keep-alive\r\n');
s.flush();
}
Using a packet sniffer, I can see the request does indeed get sent to the server, but the packet sniffer doesn't identify the protocol as HTTP like it does with other HTTP services. When I run this, the server just eventually disconnects me. I have tried to connect to other simple Apache Servers and just get a malformed request error.
What am I missing here?
You have to write another "\r\n" to the stream before the flush to tell the HTTP server that you're finished sending the headers.
Turns out I wasn't sending a blank line to the HTTP server after my request. The following minor tweak from the original works:
function sConnect(e:Event):void {
trace('connected');
s.writeUTFBytes('GET /outernet/client/rss/reddit-feeds HTTP/1.1\r\n');
s.writeUTFBytes('Host: 208.43.71.50:8080\r\n');
s.writeUTFBytes('Connection: Keep-alive\r\n\r\n');
s.flush();
}
Note the extra \r\n after the last writeUTFBytes. Thanks anyway Brian.
Edit: Thanks Graeme.
Instead of using UTF, try with ANSI/ASCII. The encoding may be the cause of the issue.
I just wasted a lot of time tracking down what is apparently a serious bug in some combinations of Flash 10 and Linux with writeMultiByte(). I would be very dubious about using writeMultiByte().
I hope this helps you.
Maybe wrong, 'ascii' encoding not supported (see http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/charset-codes.html) - use 'us-ascii'