API Endpoint only allows GET when it should take POST - asp.net-mvc

I am building a React.js front-end portion of a web application using an already existing back-end that is built with ASP.NET MVC Framework. The method in the API's controller is named Post (which should default it to a post method) and even has the [HttpPost] decorator. I have recently enabled CORS, but I am not sure if that matters.
The API also has Swagger (it's like postman if you haven't used it before) enabled, and when I call the method as POST from the swagger, it will work and return the correct data.
However, when I try to call the method from my UI component, the API endpoint will give a 405 Method Not Allowed status code.
It says that the method only allows GET, which is baffling since it is supposed to only allow POST and it works that way on swagger or if I manually travel to the URL using a browser. Has anyone had a problem like this using React components or working with ASP.NET MVC/Web API 2?
I am completely stuck...
EDIT:
I am adding the API's method for the post endpoint.
[Route("{id}/merchant/SearchMerchants")]
[HttpPost]
[AuthorizeUserPermissionsToken(Cookie)]
public Response Post(Request rq)
{ // I put a breakpoint here to debug
// some code
}
I had to redact a lot of the code but here is the post method.
But I don't think it has to do with the API endpoint.
This is because when I debug, it will not even reach the breakpoint or call the method at all, when I am using the UI. However, it will reach the breakpoint when I travel to the endpoint on the browser or use swagger.
EDIT 2:
EDIT 3: (removed EDIT 2 and moved the original headers to bottom to reduce confusion)
Pre-flight OPTIONS request headers
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host: *redacted domain*
Origin:http://localhost:49702
Pragma:no-cache
Referer:http://localhost:49702/FindMerchants
User-Agent:Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Mobile Safari/537.36
response headers to OPTIONS request:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Origin:http://localhost:49702
Allow:OPTIONS, TRACE, GET, HEAD, POST
Content-Length:0
Date:Mon, 07 Aug 2017 18:41:42 GMT
Public:OPTIONS, TRACE, GET, HEAD, POST
Server:Microsoft-IIS/10.0
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
then the real POST request headers after pre-flight:
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:154
Content-Type:application/json
Cookie: *redacted a bunch of cookies*
Host:a *redacted domain*
Origin:http://localhost:49702
Pragma:no-cache
Referer:http://localhost:49702/FindMerchants
User-Agent:Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Mobile Safari/537.36
The real response headers are like so:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Origin:http://localhost:49702
Allow:GET
Cache-Control:no-cache
Content-Length:73
Content-Type:application/json; charset=utf-8
Date:Mon, 07 Aug 2017 17:58:28 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/10.0
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
EDIT 4:
Request URL:*redacted domain*/380/merchant/SearchMerchant
Request Method:POST
Status Code:405 Method Not Allowed
Remote Address:127.0.0.1:80
Referrer Policy:no-referrer-when-downgrade
EDIT #9999 (jk):
My react component simply calls a custom data service that I wrote, which has a post method like this.
post(relativeUrl, data, apiVersion) {
var url = this.getUrl(relativeUrl, apiVersion);
var res = $.ajax({
type: 'POST',
url: url,
contentType: 'application/json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
data: JSON.stringify(data)
});
return res;
}
I simply pass relativeUrl to fetch a list related to a user account.
Before I make a call that fails (which shows 405), I use this same method to log in and update the global redux state for the app. After updating the global state, I render a different component and use this method again with another relativeUrl to fetch the list. Then I get the error. I also make sure that the login call is finished and returns and updates the state correctly before moving on.

To follow my comment,
in web.config file:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS, HEAD" />
</customHeaders>
</httpProtocol>

Related

Loading font fron CloudFront giving No 'Access-Control-Allow-Origin' header is present on the requested resource

First, I know there are tons of similar issues on StackOverflow and elsewhere. I tried them for days with no luck. So sorry if this sounds duplicate. Correct me if it is actually.
I have Heroku Rails app loading font from CloudFront. Everything else seems to load fine except that font. I get
Access to Font at
'https://domainname.herokuapp.com/assets/LigatureSymbols-2.11-722bc1af51c5e458d52834d798e4c0e8.ttf'
from origin 'null' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.
It says origin null, and access-control-allow-origin is not present. However this is the request and response data:
Request URL:https://domainname-herokuapp-com.global.ssl.fastly.net/assets/LigatureSymbols-2.11-722bc1af51c5e458d52834d798e4c0e8.ttf
Request Method:GET
Status Code:302 Found
Remote Address:151.101.0.249:443
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Accept-Ranges:bytes
Access-Control-Allow-Origin:*
Age:52
Connection:keep-alive
Content-Length:0
Content-Type:text/html; charset=utf-8
Date:Sun, 16 Apr 2017 10:40:37 GMT
Location:https://domainname.herokuapp.com/assets/LigatureSymbols-2.11-722bc1af51c5e458d52834d798e4c0e8.ttf
Server:gunicorn/19.7.1
Via:1.1 varnish
Via:1.1 vegur, 1.1 vegur
X-Cache:HIT
X-Cache-Hits:1
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Served-By:cache-hhn1527-HHN
X-Timer:S1492339237.333330,VS0,VE0
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Host:domainname-herokuapp-com.global.ssl.fastly.net
**Origin:https://staging.domainname.com**
Referer:https://domainname.herokuapp.com/assets/application-d2b73eea67437c851b6e71803bad2a6c.css
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Name
?store=true&search_type=posts
css?family=Lato:400,300,700
MgNNr5y1C_tIEuLEmicLmwLUuEpTyoUstqEm5AMlJo4.woff2
LigatureSymbols-2.11-722bc1af51c5e458d52834d798e4c0e8.ttf
MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2
icon-close-89c814d2fa53dff86b00936a7a8c836e.png
icon-bell-91b2c7d5db27d9fc9e8325dda55e73c0.png
icon-comment-35728eedd10ff36bc89c7a977ed67764.png
Origin is defined, and it should be allowing all origins. What am I doing wrong?

expires_in max-age cache control doesn't work

I can't get the max-age cache control to work properly,
I have used expires_in that resulted in a "Cache-Control:max-age=86400, public, must-revalidate" header.
But yet, the browser still sends the request to the server, at least it is defined as "304 not modified", meaning that the ETag/If-None-Match headers works properly.
I have tested it with webrick on my localhost and on heroku,
with chrome 45 and Safari.
And no, my development tools are not opened, and the "disable cache" is not checked.
I also have tried to remove the ", must_revalidate: true" of the expires_in method call.
What am I missing?
Here is the output from the network in chrome:
General:
Remote Address:127.0.0.1:3000
Request URL:http://localtest.me:3000/api/books
Request Method:GET
Status Code:304 Not Modified
Response Headers:
Access-Control-Allow-Origin:*
Access-Control-Request-Method:*
Cache-Control:max-age=86400, public, must-revalidate
Connection:Keep-Alive
Date:Tue, 08 Sep 2015 13:28:01 GMT
Etag:W/"1f1b2d0b822830bc74e7c47a116205be"
Server:WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:c70d4715-dcff-4558-85af-9d21556d406a
X-Runtime:0.553353
X-Xss-Protection:1; mode=block
Request Headers:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,fr;q=0.6,he;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Host:localtest.me:3000
If-None-Match:W/"1f1b2d0b822830bc74e7c47a116205be"
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36
And here is the ruby code:
before_action :cache_control, only: [:index, :show]
def cache_control
expires_in 1.day, public: true, must_revalidate: true
end
Well, the headers are fine, it is just a meter of how browsers treats the reload button or shortcut keys.
I found the answer here: https://stackoverflow.com/a/16510707/789658
Here are the findings in chrome:
Pressing Enter on the address bar respects the "max-age" and doesn't send a request to the server.
The reload button or Cmd+R sends a request to the server with If-Modified-Since and will return 304 if resource wasn't modified since...
Cmd+Shift+R sends a request to the server without even If-Modified-Since

DART HttpRequest does not provide authorization header for CORS OPTIONS request

I try to do a POST request with HttpRequest (dart:html) to call a rest service secured with basic authentication.
HttpRequest request = new HttpRequest(); // create a new XHR
var url = "http://localhost:8082/xyz";
request.open("POST", url, async: false); // POST the data to the server
String username = "foo";
String password = "bar";
final auth = CryptoUtils.bytesToBase64(UTF8.encode("$username:$password"));
request.setRequestHeader('authorization',"Basic $auth");
request.setRequestHeader('content-type',"application/json");
request.setRequestHeader("accept", "application/json");
String jsonData = '{"language":"dart"}'; // etc...
request.send(jsonData); //exception 401 Unauthorized
Before performing the POST call the OPTIONS call is performed (issued by dart:html) without the authorization header. This leads into an 401 Unauthorized response.
Request header:
Accept:*/*
Accept-Encoding:
gzip,deflate,sdch
Accept-Language:
en-US,en;q=0.8
Access-Control-Request-Headers:
authorization, content-type, accept
Access-Control-Request-Method:
POST
Cache-Control:
max-age=0
Connection:
keep-alive
Host:
localhost:8082
Origin:
http://localhost:63342
Referer:
http://localhost:63342/dart_client/test/all_test.html
User-Agent:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.0 (Dart) Safari/537.36
Reponse header:
Content-Length:
0
Date:
Mon, 02 Feb 2015 23:33:58 GMT
Server:
Jetty(9.2.7.v20150116)
WWW-Authenticate:
basic realm="xyzrealm"
Is there a way to provide the authorization header to the OPTIONS call?
Any suggestions would be great. Thanks
The OPTIONS request is made by the browser automatically and you can't modify that request. The server needs to allow the OPTIONS preflight request without authentication.
See http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0
The user credentials are excluded.

CORS in rails-api and angularJs

I've been trying out all kinds of solutions from the countless other questions on this topic, without any luck...
I'm trying to setup a rails-api project, with a front-end in AngularJs. They will be in different domains. I can make GET requests without any problem. But when I try to do a PUT, I get on Chrome console:
XMLHttpRequest cannot load http://0.0.0.0:3000/thingies/1.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:9000' is therefore not allowed access
Here's what my failed request looks like:
Remote Address:0.0.0.0:3000
Request URL:http://0.0.0.0:3000/thingies/1
Request Method:OPTIONS
Status Code:404 Not Found
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,ja;q=0.6,ko;q=0.4,pt;q=0.2,ro;q=0.2,zh-CN;q=0.2
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:PUT
Cache-Control:no-cache
Connection:keep-alive
Host:0.0.0.0:3000
Origin:http://localhost:9000
Pragma:no-cache
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36
Response Headersview source
Connection:Keep-Alive
Content-Length:17164
Content-Type:text/html; charset=utf-8
Date:Tue, 26 Aug 2014 06:48:06 GMT
Server:WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24)
X-Request-Id:xxxxxx-xxxxxxx-xxxxxx-xxxxxxxxxx
X-Runtime:0.027031
Here's my app.js in AngularJs:
angular
.module('myApp', [
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'restangular',
])
.config(function ($routeProvider,RestangularProvider, $httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common["X-Requested-With"];
$httpProvider.defaults.headers.common["Accept"] = "application/json";
$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeCtrl'
.otherwise({
redirectTo: '/'
});
RestangularProvider.setBaseUrl('http://0.0.0.0:3000');
});
This is in my Rails project:
application.rb:
class Application < Rails::Application
config.action_dispatch.default_headers.merge!({
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => '*'
})
end
My routes.rb, application_controller.rb and thingy_controller are the default scaffolded files. (I've tried modifying them according to other solutions for CORS, without any luck.)
I've used POSTMAN (Chrome Extension) as well, to see if I could use PUT. The requests went through without problems.
I'd really appreciate if someone could point me in the right direction with this!
Try add { 'Content-Type': 'application/x-www-form-urlencoded' } in your $http request like that
$http({
method : 'POST',
url : 'backend.json',
data : $.param($scope.yourFormData), // pass in data as string, important!
headers: { 'Content-Type': 'application/x-www-form-urlencoded' } // set the appropriate headers
})
The Problem is that CORS is blocking your requests. You have to provide the Service and the Application on the same host with the same port. To avoid this problem you could use a Proxy to "map" the url of the service to the url of your application.
Cheers
Nighthawk

Telerik MVC Extensions: Grid: During Ajax binding calls why is so much data posting back in the query string?

I am using Ajax binding with the Grid and ran into a problem where ASP.NET MVC was throwing a HttpRequestValidationException when I attempted an operation on the grid that invoked the Ajax call (like sorting).
Using Fiddler I was able to determine my browser was attempting to post back my entire model in the query string and there were some characters that would have triggered ASP.NET's request validation.
I was able to work around this by simply adding
[ValidateInput(false)]
to my controller action.
I'm wondering why was the grid sending back so much data? And is this a symptom of a bug in my code or Telerik's?
Here is what I saw in Fiddler (note the extremely long query string, even though the HTTP verb is "POST").
POST http://127.0.0.1:52601/MyController/DatabindGrid?Items=System.Collections.ObjectModel.Collection%601%5BPMyNamespace.Data.ViewEntities.Alert%5D&DetailsClientUrl=&GetJsonUrl=%2FMonitor%2FGetGridJson&ViewName=&CurrentItem=&PageTitle=My%20Web%20Page&CopyrightText=Copyright%20%26%23x00A9%3B%202004-2010%20My%20Company%20Corporation&BrowserCapabilities=&OemName=&UiVersion=20101123 HTTP/1.1
Referer: http://ipv4.fiddler:52601/MyController/MyAction
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: text/plain, */*; q=0.01
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host: 127.0.0.1:52601
Content-Length: 56
Connection: Keep-Alive
Pragma: no-cache
Cookie: ASP.NET_SessionId=bvgwuno4bounqio2werepkw4; .ASPXAUTH=612E18BB916F720D13A0F0D1695A86079B94DFE94A3BF5A9A8F19E35A37AE987282B7B684201C112CEC6081181E3D1C52C5517A66D9158E4CF83C1C3F523EE32FF783BD2E3B6E0A42A35E1874E63BA76C7735F9E8ABBA4E58BF61EB29DA03789E07A201A1BA9E7B85F941516ED7EA26E3E8E1E65D0836F39A109201E357EE97478D1A359B3FB4B4AD4C64A02A0CE7BBB39DC8FE1F73B179F284A14CF55D9C67D
page=1&size=10&orderBy=LocationName-asc&groupBy=&filter=
Rick,
I think you might be interested in this...
http://tv.telerik.com/watch/aspnet-mvc/video/building-a-responsive-site-with-mvc
very detailed and informative.
~AZee

Resources