difference between two http requests - ajax

I have two http requests, one written in curl, one written in javascript in chrome. The curl request works but the chrome request doesn't, but i'm not sure why.
Chrome:
PUT /api/Account HTTP/1.1
Host: mydomain.co.nz
Connection: keep-alive
Content-Length: 152
Pragma: no-cache
Cache-Control: no-cache
Authorization: Bearer eyJhb..
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Content-Type: multipart/form-data; boundary=--------------------------33e4cd665cd7a003
Accept: application/json
Referer: http://localhost:4200/conversations
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
--------------------------33e4cd665cd7a003
Content-Disposition: form-data; name="data"
{"isoncall" : true}
--------------------------33e4cd665cd7a003--
curl:
PUT /api/Account HTTP/1.1
Host: mydomain.co.nz
User-Agent: curl/7.51.0
accept: application/json
authorization: Bearer eyJhbGciO....
cache-control: no-cache
Content-Length: 158
Expect: 100-continue
Content-Type: multipart/form-data; boundary=--------------------
----a8c24af99c272f79
--------------------------a8c24af99c272f79
Content-Disposition: form-data; name="data"
{"isoncall" : true}
--------------------------a8c24af99c272f79--
The error i'm getting with chrome is:
[{"error":"Unexpected end of Stream, the content may have already been read by another component. ","type":"IOException","stack":" at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.d__41.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.WebUtilities.MultipartReader.d__20.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Http.Features.FormFeature.d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.ModelBinding.FormValueProviderFactory.d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.DefaultControllerArgumentBinder.d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__22.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__20.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at IdentityModel.AspNetCore.ScopeValidation.ScopeValidationMiddleware.d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware1.d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationMiddleware.d__7.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.d__7.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at Celo.Api.Middleware.Exceptions.ExceptionHandlingMiddleware.d__5.MoveNext() in D:\a\1\s\src\Celo.Api\Middleware\Exceptions\ExceptionHandlingMiddleware.cs:line 41"}]
I'm not sure how this is failing.
for reference the curl command is:
curl -X PUT https://mydomain.co.nz/api/Account -H 'accept: application/json' -H 'authorization: Bearer eyJhb..' -H 'cache-control: no-cache' -F 'data={"isoncall" : true}'
and the javascript call is:
let xhr:XMLHttpRequest = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('200', xhr.response)
//resolve(<MyEntity>JSON.parse(xhr.response));
} else {
console.log('err', xhr.response)
//reject(xhr.response);
}
}
};
xhr.open('PUT', 'https://mydomain.co.nz/api/Account', true);
xhr.setRequestHeader("Accept", "application/json")
xhr.setRequestHeader("Authorization", this.authService.getAuth())
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=--------------------------33e4cd665cd7a003')
xhr.send(`--------------------------33e4cd665cd7a003
Content-Disposition: form-data; name="data"
{"isoncall" : true}
--------------------------33e4cd665cd7a003--`)

A clear difference between the two requests is that in your XHR request, you don't prefix the boundary in the body of the request with two dashes as required.
If you look at the request generated by CURL, you will see that the two boundaries have two additional dashes prefixed (when compared to the boundary in the header), as well as two extra dashes suffixed to the last boundary of the body. You don't have the prefixes in your javascript code.
Now, having said that, I can suggest two possible solutions:
Fix your current code - this is possibly a quick fix.
As mentioned above, you need to add the additional -- prefix to the boundary in the body.
Secondly, I would avoid multiline strings the way you have them and use \n as line separator.
This would result in the following javascript:
xhr.open('PUT', 'https://mydomain.co.nz/api/Account', true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Authorization", this.authService.getAuth());
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=--------------------------33e4cd665cd7a003')
xhr.send(`----------------------------33e4cd665cd7a003\n' +
'Content-Disposition: form-data; name="data"\n\n' +
'{"isoncall" : true}\n\n' +
'----------------------------33e4cd665cd7a003--');
You could also switch to the XHR FormData API and avoid dealing with all this manually.
var formData = new FormData();
formData.append("data", '{"isoncall" : true}');
xhr.open('PUT', 'https://mydomain.co.nz/api/Account', true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Authorization", this.authService.getAuth());
xhr.send(formData);

Related

Dynamics 365 WebApi - BATCH request - Error - The message header ' ' is invalid

Anyone is facing the follow error message, trying to execute a BATCH request for Dynamics 365 WebApi? I'm using Postman.
{
"Message": "The message header ' ' is invalid. The header value must be of the format '<header name>: <header value>'.",
"ExceptionMessage": "The message header ' ' is invalid. The header value must be of the format '<header name>: <header value>'.",
"ExceptionType": "Microsoft.OData.ODataException",
"StackTrace": " at Microsoft.OData.MultipartMixed.ODataMultipartMixedBatchReaderStream.ValidateHeaderLine(String headerLine, String& headerName, String& headerValue)\r\n at Microsoft.OData.MultipartMixed.ODataMultipartMixedBatchReaderStream.ReadHeaders()\r\n at Microsoft.OData.MultipartMixed.ODataMultipartMixedBatchReaderStream.ProcessPartHeader(String& contentId)\r\n at Microsoft.OData.MultipartMixed.ODataMultipartMixedBatchReader.SkipToNextPartAndReadHeaders()\r\n at Microsoft.OData.ODataBatchReader.ReadImplementation()\r\n at Microsoft.OData.ODataBatchReader.InterceptException[T](Func`1 action)\r\n at Microsoft.Crm.Extensibility.OData.CrmODataBatchHandler.<ParseBatchRequestsAsyncImplementationAsync>d__16.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Crm.Extensibility.OData.CrmODataBatchHandler.<>c__DisplayClass9_0.<<ParseBatchRequestsAsync>b__0>d.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.PowerApps.CoreFramework.ActivityLoggerExtensions.<ExecuteAsync>d__11`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Xrm.Telemetry.XrmTelemetryExtensions.<ExecuteAsync>d__6`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Crm.Extensibility.OData.CrmODataBatchHandler.<ParseBatchRequestsAsync>d__9.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.OData.Batch.DefaultODataBatchHandler.<ProcessBatchAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Batch.HttpBatchHandler.<SendAsync>d__0.MoveNext()",
"ErrorCode": "0x0"
}
Image of Postman headers
Here's my Body Content:
--batch_AAA123
Content-Type: multipart/mixed;boundary=changeset_BBB456
--changeset_BBB456
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-ID: 1
POST https://copasa.crm2.dynamics.com/api/data/v9.1/tasks HTTP/1.1
Content-Type: application/json;type=entry
Accept: application/json
{"subject":"Task 1 in batch","regardingobjectid_account_task#odata.bind":"https://copasa.crm2.dynamics.com/api/data/v9.1/accounts(1AD045E1-7DE4-E911-A812-000D3AC058C3)"}
--changeset_BBB456
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-ID: 2
POST https://copasa.crm2.dynamics.com/api/data/v9.1/tasks HTTP/1.1
Content-Type: application/json;type=entry
Accept: application/json
{"subject":"Task 2 in batch","regardingobjectid_account_task#odata.bind":"https://copasa.crm2.dynamics.com/api/data/v9.1/accounts(1AD045E1-7DE4-E911-A812-000D3AC058C3)"}
--changeset_BBB456--
--batch_AAA123
Content-Type: application/http
Content-Transfer-Encoding:binary
GET https://copasa.crm2.dynamics.com/api/data/v9.1/accounts(1AD045E1-7DE4-E911-A812-000D3AC058C3)/Account_Tasks?$select=subject HTTP/1.1
Accept: application/json
--batch_AAA123--
Nothing looks wrong except the extra white lines between Batch request unique identifier & headers, the error maybe coming because of that. Remove the extra white lines like below:
--batch_AAA123
Content-Type: multipart/mixed;boundary=changeset_BBB456
--changeset_BBB456
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-ID: 1
POST https://copasa.crm2.dynamics.com/api/data/v9.1/tasks HTTP/1.1
Content-Type: application/json;type=entry
Accept: application/json
{"subject":"Task 1 in batch","regardingobjectid_account_task#odata.bind":"https://copasa.crm2.dynamics.com/api/data/v9.1/accounts(1AD045E1-7DE4-E911-A812-000D3AC058C3)"}
--changeset_BBB456
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-ID: 2
POST https://copasa.crm2.dynamics.com/api/data/v9.1/tasks HTTP/1.1
Content-Type: application/json;type=entry
Accept: application/json
{"subject":"Task 2 in batch","regardingobjectid_account_task#odata.bind":"https://copasa.crm2.dynamics.com/api/data/v9.1/accounts(1AD045E1-7DE4-E911-A812-000D3AC058C3)"}
--changeset_BBB456--
--batch_AAA123
Content-Type: application/http
Content-Transfer-Encoding:binary
GET https://copasa.crm2.dynamics.com/api/data/v9.1/accounts(1AD045E1-7DE4-E911-A812-000D3AC058C3)/Account_Tasks?$select=subject HTTP/1.1
Accept: application/json
--batch_AAA123--
I had the same problem only it was saying that the message header '\t' was invalid. On one of my blank lines I had tab character that I couldn't see. Once I found it and removed it, my request went through just fine.

Intermittent Server cannot set status after HTTP headers have been sent

I am getting an intermittent error in the event logs "Server cannot set status after HTTP headers have been sent". The webapi site is working fine and delivering the correct output even when this happens.
Exception information:
Exception type: HttpException
Exception message: Server cannot set status after HTTP headers have been sent. at System.Web.HttpResponse.set_StatusCode(Int32
value) at System.Web.HttpResponseWrapper.set_StatusCode(Int32
value) at
System.Web.Http.WebHost.HttpControllerHandler.d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at
System.Web.Http.WebHost.HttpControllerHandler.d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at
System.Web.Http.WebHost.HttpControllerHandler.d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at System.Web.TaskAsyncHelper.EndTask(IAsyncResult ar) at
System.Web.HttpTaskAsyncHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult
result) at
System.Web.HttpApplication.CallHandlerExecutionStep.InvokeEndHandler(IAsyncResult
ar) at
System.Web.HttpApplication.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult
ar)
The response object is manipulated directly (the format of the json is not known until runtime) as follows.
var response= HttpContext.Current.Response;
response.StatusCode = (int) HttpStatusCode.OK;
response.Headers.Add("X-Robots-Tag", "noindex, nofollow");
response.Write("Some json");
response.Flush();
response.End();
response.End is required, I do not understand why, a similar error occurs if this line is missed out.
Why does this happen, and is there a better way of doing it?
Since you tagged your question with asp.net-web-api I assume that you are using that code in an api controller method. If so, I suggest returning the unknown Json like this:
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Some json", System.Text.Encoding.UTF8, "application/json")
};
response.Headers.Add("X-Robots-Tag", "noindex, nofollow");
return response;
Above code was taken from the following links and adapted:
Put content in HttpResponseMessage object
and
Add a custom response header in ApiController (questions and answers on SO)

Spring MVC Restful 406 Not Acceptable Error

I know this question has been asked before, and I've checked every message of Spring MVC with the 406 error message and I am beside myself not knowing how to fix this problem since I've tried just about everything put fourth by these previous answers.
This one web-service takes an email address, and returns back a user object in JSON. I can tell you the unit test works great. And I know we pass the Spring Security, we are executing the servlet ... the only problem now is the JSON output ... I don't get that, I get this error message.
So, to be exact:
Spring Core: 4.2.4.RELEASE
Spring Security: 4.0.3.RELEASE
Jackson Faster XML: 2.6.5 (core, databind, annotations)
2.7.0 doesn't seem to work yet ...
Here is the springmvc-servlet.xml:
<context:annotation-config />
<context:component-scan base-package="com.agmednet.server.controller" />
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.agmednet.server.HibernateAwareObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss.SSS"></constructor-arg>
</bean>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Here is the controller:
#Controller
#RequestMapping("/users")
public class UserAccountController
{
#Autowired
private UserAccountService userAccountService;
#RequestMapping(value = "/email/{email:.*}", method = RequestMethod.GET)
public #ResponseBody UserAccountEntity getByEmailAddress(#PathVariable("email") String email)
{
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = null;
if (principal instanceof User)
{
user = ((User) principal)
}
UserAccountEntity userAccount = userAccountService.getByEmailAddress(email);
return userAccount;
}
}
As you can see, I have the Accept header setup, I have the #ResponseBody annotation.
I have a SimpleCORSFilter Code on top of this:
#Component
public class SimpleCORSFilter implements Filter
{
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type, Accept, If-Modified-Since, openam_token");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig){}
public void destroy(){}
}
As you can see, this accepts my custom header for an "openam_token", but is has
"Accept" and "Content-Type" as well.
I am calling this from a linux box behind a firewall, so I have to SSH into the machine, and execute this curl statement:
curl -v -i -X GET -H "openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*" -H "Content-Type: application/json, text/html" -H "Accept: application/json, text/html" backend.spring.mycompany.net:8080/services/api/users/email/user4252002#mycompany.com
So, here is what I am sending via curl in the request:
* Trying 10.0.4.107...
* Connected to backend.spring.agmednet.net (10.0.4.107) port 8080 (#0)
> GET /services/api/users/email/user4252002#agmednet.com HTTP/1.1
> User-Agent: curl/7.40.0
> Host: backend.spring.agmednet.net:8080
> openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*
> Content-Type: application/json, text/html
> Accept: application/json, text/html
And here is the response:
< HTTP/1.1 406 Not Acceptable
HTTP/1.1 406 Not Acceptable
< Server: Apache-Coyote/1.1
Server: Apache-Coyote/1.1
< Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
< Access-Control-Max-Age: 3600
Access-Control-Max-Age: 3600
< Access-Control-Allow-Headers: x-requested-with, Content-Type, Accept, If-Modified-Since, openam_token
Access-Control-Allow-Headers: x-requested-with, Content-Type, Accept, If-Modified-Since, openam_token
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
Pragma: no-cache
< Expires: 0
Expires: 0
< X-XSS-Protection: 1; mode=block
X-XSS-Protection: 1; mode=block
< X-Frame-Options: DENY
X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
X-Content-Type-Options: nosniff
< Set-Cookie: JSESSIONID=76C4B28DD0B5D88EB9341944BDBCD045; Path=/services/; HttpOnly
Set-Cookie: JSESSIONID=76C4B28DD0B5D88EB9341944BDBCD045; Path=/services/; HttpOnly
< Content-Type: text/html;charset=utf-8
Content-Type: text/html;charset=utf-8
< Content-Language: en
Content-Language: en
< Content-Length: 1110
Content-Length: 1110
< Date: Wed, 20 Jan 2016 14:30:28 GMT
Date: Wed, 20 Jan 2016 14:30:28 GMT
<!DOCTYPE html>
<html><head>
<title>Apache Tomcat/8.0.30 - Error report</title>
</head>
<body>
<h1>HTTP Status 406 - </h1>
<div class="line"></div><p><b>type</b> Status report</p>
<p><b>message</b> <u></u></p>
<p><b>description</b>
<u>The resource identified by this request is only capable of generating
responses with characteristics not acceptable according to the request*
Connection #0 to host backend.spring.agmednet.net left intact
"accept" headers.</u></p>
<hr class="line"><h3>Apache Tomcat/8.0.30</h3></body></html>
Ultimately, this is the error message listed above:
The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request* Connection #0 to host backend.spring.mycompany.net left intact
"accept" headers.
So, I am using #ResponseBody, I am using the latest Jackson 2.x version. I am following all the suggestions from previous questions and I still can't get this to work.
Any help would be much appreciated.
The #EnableWebMVC wasn't the problem, and everything you see in the question is 100% correct. I have two other web-services that worked fine. The problem ultimately was with the curl statement itself:
curl -v -i -X GET -H /
"openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*" /
-H "Content-Type: application/json, text/html" /
-H "Accept: application/json, text/html" /
backend.spring.mycompany.net:8080/services/api/users/email/user4252002#mycompany.com
If you notice, the URL and the path variable is not in quotes.
if you notice, the email address has an # symbol in it, which I found out means something to curl. So, what I did was change my curl to the following.
curl -v -i -X GET -H /
"openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*" /
-H "Content-Type: */*" /
-H "Accept: */*" /
"backend.spring.mycompany.net:8080/services/api/users/email/user4252002%40mycompany%2Ecom"
1) I encoded the email address myself # to %40 and period-dot to %2E
You can use whatever tool you meant to encode the path variable.
2) Even though I am returning a java object transformed into JSON, I changed headers "Accept" and "Content-Type" to "/".
That was it. This worked and the 406 error message went away.

Spring Boot swallowing Access-Control-Request-Headers on OPTIONS preflight

I have a Spring Boot REST application that has a very simple CORS filter on it. What I want to do is dynamically respond to the values in the Access-Control-Request-Headers header, rather than provide a specific list. The common wisdom seems to be the explicitly set the values returned in the "Access-Control-Allow-Headers", however we will be white-listing a set of origins and want to allow any headers they send. I cannot find a way to parrot back the value of Access-Control-Allow-Headers in Access-Control-Request-Headers.
Here's the code
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS"); // will need to enable other methods when/as implemented
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
((HttpServletRequest) servletRequest).getHeader("Access-Control-Request-Headers"));
filterChain.doFilter(servletRequest, servletResponse);
}
With this request & response from Chrome (when we were hard-coding the value of Access-Control-Allow-Headers)
Remote Address:10.199.240.16:443
Request URL:https://myapp.com/gradebooks/5566669e-e4b0-d05e-0150-98d7ffffffff/assignments/3ad7f1e7-679b-4d8b-856e-d2e3589eaad6
Request Method:OPTIONS
Status Code:200 OK
Response Headers
view source
Access-Control-Allow-Methods → POST, PUT, GET, DELETE, OPTIONS
Access-Control-Max-Age → 3600
Content-Type → application/hal+json; charset=UTF-8
Date → Tue, 21 Jul 2015 20:42:29 GMT
Server → Jetty(9.2.9.v20150224)
Transfer-Encoding → chunked
X-Application-Context → application
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:PUT
Connection:keep-alive
Host:gbservices-api.dev-prsn.com
Origin:http://localhost:3000
Referer:http://localhost:3000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36
This is the error
XMLHttpRequest cannot load
https://myapp.com/gradebooks/5566669e-e4b0-d05e-0150-98d7ffffffff/assignments/3ad7f1e7-679b-4d8b-856e-d2e3589eaad6.
Request header field Content-Type is not allowed by
Access-Control-Allow-Headers.
What I've found debugging into the filter is that the Access-Control-Request-Headers, and only that header, is missing by the time it gets to the filter. Misspell the header and it arrives, so it seems that something is intercepting the header and discarding it before it gets to my filter...

Guice servlet 405 err: seems to not set Content-type set to "text/json" for MediaType.APPLICATION_JSON

I'm making a call from jQGrid to a Guice servlet that has the following binding:
#Produces({MediaType.APPLICATION_JSON})
#Path("/{param}")
public String getJson(#PathParam("param") String param) {
...
return return json.toString();
}
Requesting the url directly, I can see the JSON. When jqgrid executes the request, I get 405 method not allowed response. I've seen this happen before when the returning page doesn't have the Content-type set to "text/json" (jqgrid is not very flexible here).
HERE IS THE REQUEST:
Key Value
Request POST /myapp/json/jqgrid/json ... HTTP/1.1
x-requested-with XMLHttpRequest
Accept-Language en-us
Referer http://localhost:8080/myapp/myPage...
Accept application/json, text/javascript, /
Content-Type application/x-www-form-urlencoded
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host localhost:8080
Content-Length 63
Connection Keep-Alive
Cache-Control no-cache
HERE IS THE RESPONSE:
Key Value
Response HTTP/1.1 405 Method Not Allowed
Server Apache-Coyote/1.1
Allow GET,OPTIONS,HEAD
Content-Type text/html;charset=utf-8
Content-Length 1034
Any thoughts on how to get the guice servlet to set the Content-type to "text/json" and allow the response?
This one is solved. I was using a #GET annotation and jQGrid was issuing a post. I changed the #POST and it started working. This may solve the problem for others with related 405 errors.

Resources