Symfony3 fosrest api method options not allowed - symfony

I've got an api build in Symfony 3 with the FOSrestBundle and NelmioCORSBundle.
In my controller i have an method postSaveLotteryAction() which fosrest converts to the route /lotteries/saves/lotteries
Now my ReactJS application uses Axios to make a xhr (ajax) request to the api (that is hosted on a diffrent domain) and because of CORS it first sends out a OPTIONS request.
My apache server is configured correctly with the correct headers as shown below.
The message shown by Symfony is 405 method not allowed. But everything points to the OPTIONS method is allowed.
Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 1000
Allow:
Connection: Keep-Alive
Content-Length: 250
Content-Type: text/html; charset=iso-8859-1
Date: Wed, 11 Apr 2018 07:03:30 GMT
Keep-Alive: timeout=2, max=100
Server: Apache/2
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: api.naamloting.nl
Origin: http://beta.naamloting.nl
This is my bin/console d:r output where i've added in the route.yml the GET, OPTIONS, POST methods.
get_lottery GET|POST|OPTIONS ANY ANY /lotteries/{uuid}
get_lottery_stats GET|POST|OPTIONS ANY ANY /lottery/stats
post_lottery_save_lottery GET|POST|OPTIONS ANY ANY /lotteries/saves/lotteries
get_lottery_image GET|POST|OPTIONS ANY ANY /lotteries/{nameOfWinner}/image
get_lottery_ticket GET|POST|OPTIONS ANY ANY /lotteries/{nameOfWinner}/ticket
Also here is my config.yml (partially) so it's clearer to see what maybe causes it.
# Nelmio CORS
nelmio_cors:
defaults:
allow_origin: ['*']
allow_methods: ["POST", "PUT", "GET", "DELETE", "OPTIONS"]
allow_headers: ["content-type"]
max_age: 3600
paths:
'^/lottery': ~
'^/lotteries': ~
# FOS REST Bundle
fos_rest:
body_listener: true
param_fetcher_listener: true
view:
view_response_listener: 'force'
formats:
jsonp: true
json: true
xml: false
rss: false
mime_types:
json: ['application/json', 'application/x-json']
jpg: 'image/jpeg'
png: 'image/png'
jsonp_handler: ~
routing_loader:
default_format: json
include_format: false
format_listener:
rules:
- { path: ^/, priorities: [ json, jsonp ], fallback_format: ~, prefer_extension: true }
exception:
enabled: true
exception_controller: 'fos_rest.exception.controller:showAction'

SOLVED
Looking at the error page it seems to me that Symfony was not the problem and i was correct.
Apache was the troublemaker that didn't allow the OPTIONS method so it always returned an 405 not allowed.
I added the method type and the request is handled correctly.

It seems that sometimes there could be happening a "preflight" OPTIONS request with the real required method in the HEADER.
I see that you allow "PUT" method in nelmio, but not in routes. Try allowing PUT in routes and see if that fixes the problem.
More info:
https://www.html5rocks.com/en/tutorials/cors/

Related

How to configure Api-platform to return simple JSON instead of JSON-LD?

I'm trying to use refine.dev with Api-platform, but all the responses are in JSON-LD, and I need them as simple JSON.
How can I configure that?
When you are declaring your collectionOperations or itemOperiation in your entity you can set the needed formats.
collectionOperations: [
'get ' => [
'formats' => ['json'],
],
You can look at this documentation
https://api-platform.com/docs/core/content-negotiation/
You need to send requests specifying Header Accept: application/json
GET /api/action
Host: example.com
Accept: application/json
Content-Type: application/json
Content-Length: 48
If you want json to be the default in Swager UI, then you can specify the type globally in the config/packages/api_platform.yaml file
api_platform:
formats:
json: ['application/json']
Try to use this code :
#ApiResource(formats= {"json"})
It works for me.

React-admin + api-platform - Content-Range

I have 2 applications, both run on the docker. First backend (symfony 5 + api platform) on port 8080, second frontend(react + react-admin) on port 3000.
I can see the table to items, but when I try to load items from backend, I see all time the same bug:
index.js:1 Error: The Content-Range header is missing in the HTTP Response. The simple REST data provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?
frontend:
ReactDOM.render(
<Admin dataProvider={simpleRestProvider('http://localhost:8080/api')}>
<Resource name="pharmacies" list={PharmacyList} edit={PharmacyEdit} create={PharmacyCreate} icon={PharmacyIcon}/>
</Admin>,
document.getElementById('root')
);
I've had a problem with CORS, so I reconfigured the nelmio_cors.yaml:
defaults:
allow_credentials: false
allow_origin: [ ]
allow_headers: [ ]
allow_methods: [ ]
expose_headers: [ 'Content-Range' ]
max_age: 0
hosts: [ ]
origin_regex: false
forced_allow_origin_value: ~
paths:
'^/api/':
allow_origin: [ '*' ]
allow_headers: [ '*' ]
allow_methods: [ 'POST', 'PUT', 'GET', 'DELETE' ]
max_age: 3600
'^/':
origin_regex: true
allow_origin: [ '^http://localhost:[0-9]+' ]
allow_headers: [ '*' ]
allow_methods: [ 'POST', 'PUT', 'GET', 'DELETE' ]
max_age: 3600
hosts: [ '^api\.' ]
The response header:
Server: nginx/1.19.5
Content-Type: application/ld+json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/7.4.13
Vary: Accept
X-Content-Type-Options: nosniff
X-Frame-Options: deny
Cache-Control: no-cache, private
Date: Sun, 21 Feb 2021 13:00:55 GMT
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: content-range
Link: <http://localhost:8080/api/docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
ETag: "0eeb89535116e4257a2152e977020a7a"
X-Debug-Token: 0f9844
X-Debug-Token-Link: http://localhost:8080/_profiler/0f9844
X-Robots-Tag: noindex
Where is my mistake? What am I doing wrong? It's a problem with frontend app, symfony config(nelmo) or http server (nginx)? I read a lot of posts on SOF/github and other blogs. Nothing can help.
https://marmelab.com/react-admin/DataProviders.html - I tried to disable it in cors headers and force this header on nelmo/api-platform. It Access-Control-Expose-Headers: content-range doesn't help.

How to set Cache-Control to no-cache in Symfony - FOSHttpCacheBundle

Problem: Hitting back button in browser renders the cached version of the secure page even after logout.
I'm trying to solve this using FOSHttpCacheBundle. Here is my config:
fos_http_cache:
cache_control:
defaults:
overwrite: true
rules:
-
match:
path: ^/
headers:
cache_control: { no_cache: true }
While it is setting the Cache-Control:no-cache, private but there is no Pragma: no-cache and Expires: -1 headers defined which according to docs should be defined.
Here's my Response Headers:
Cache-Control:no-cache, private
Connection:Keep-Alive
Content-Type:text/html; charset=UTF-8
Date:Tue, 03 May 2016 09:03:49 GMT
Keep-Alive:timeout=5, max=95
Server:Apache/2.4.9 (Win64) PHP/5.5.12
Transfer-Encoding:chunked
X-Cache-Debug:1
X-Debug-Token:050e09
X-Debug-Token-Link:/app_dev.php/_profiler/050e09
X-Powered-By:PHP/5.5.12
Someone please explain what am I missing!!
Thanks

Guard create session async

I am using guard for user authentication, login is handled by html fetch api.
If login is successfull I get token for js auth to api, but I want after page update user to be logged in, but it's not.
In response I see set cookie for PHPSESSID and REMEMBERME but it's look like this cookie is not persisted.
I'm not sure, where can be problem, it looks like guard make his work just fine.
request is not cross-domain.
request headers:
GET /login/check-facebook?code=xxx HTTP/1.1
Pragma: no-cache
Cache-Control: no-cache
accept: application/json
content-type: application/json
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36
x-api-token: anon.
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en,cs;q=0.8,en-US;q=0.6
DNT: 1
response headers:
HTTP/1.1 200 OK
Server: nginx/1.8.0
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.6.16
Set-Cookie: PHPSESSID=xxx; path=/; HttpOnly
Cache-Control: no-cache
X-Debug-Token: edb1db
X-Debug-Token-Link: /_profiler/edb1db
Date: Tue, 12 Jan 2016 15:12:32 GMT
Set-Cookie: REMEMBERME=xxx; expires=Tue, 19-Jan-2016 15:12:32 GMT; Max-Age=604800; path=/; httponly
Firewall:
main:
provider: db_provider
stateless: false
remember_me:
secret: "%secret%"
lifetime: 604800 # 1 week in seconds
path: /
always_remember_me: true
pattern: ^/
anonymous: ~
logout: ~
guard:
authenticators:
- authenticator.facebook
- authenticator.email
entry_point: authenticator.facebook
Fount it.
In fetch api option credentials: 'same-origin' must be set.
Similar thing must be send with jquery or xhr. withCredentials: true

SignalR routing issue, get 200 ok but response empty

I have an existing MVC application which I am integrating a hub into, now I have setup the hub like so:
routeTable.MapHubs("myapp/chat/room", new HubConfiguration { EnableCrossDomain = true, EnableDetailedErrors = true, EnableJavaScriptProxies = true });
Then in the clientside I am connecting like so:
var connection = $.hubConnection(SystemConfiguration.ServiceUrl + "/myapp/chat/room", { useDefaultPath: false });
var hub = this.Connection.createHubProxy("ChatHub"); // Same name as on the hub attribute
connection.start().done(function(){ /* do stuff */});
Then I see the HTTP Request like so:
http://localhost:23456/myapp/chat/room/negotiate?_=1374187915970
Response Headers
Access-Control-Allow-Cred... true, true
Access-Control-Allow-Head... content-type, x-requested-with, *
Access-Control-Allow-Meth... GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Orig... http://localhost:34567, http://localhost:34567
Access-Control-Max-Age 10000
Cache-Control no-cache
Content-Length 420
Content-Type application/json; charset=UTF-8
Date Thu, 18 Jul 2013 22:52:18 GMT
Expires -1
Pragma no-cache
Server Microsoft-IIS/8.0
X-AspNet-Version 4.0.30319
X-Content-Type-Options nosniff
Request Headers
Accept application/json, text/javascript, */*; q=0.01
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Host localhost:23456
Origin http://localhost:34567
Referer http://localhost:34567/myapp/chat?chatId=1764a2e3-ff6f-4a17-9c5f-d99642301dbf
User-Agent Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0
The response though contains no body, its got a 200 status though... I am debugging on the server and the hub methods are never hit. The only non standard thing in this scenario is that I have a custom CORS HttpModule which intercepts traffic and appends the CORS required headers, as you can see in the response, so not sure if this confuses SignalR's CORS support in some way. Anyway I can see the HttpModule being hit so it goes past there fine, but is somehow lost between there and the hub.
Tried googling but not much info on this topic...
The issue seems to be down to my CORS handling at HttpModule level, it must somehow conflict with SignalR... if I put a check in the module to see if the URL contains "chat/room" and just ignore the request if needed it then works fine, however it feels like a hack, but at least it works now.

Resources