Recently I developed an API with Spring Boot. All the tests on the local environment went well with Postman. However, when deploying to prod through HAProxy, I got this CORS error:
There are also other errors regarding missing headers, origin…
There are some solutions available, such as adding code to my Spring Boot code base. I don’t like this method since it’s not pure
.
Why add non-business code in API?
That’s why I need to find another solution.
It turned out, that the solution is simple.
If you prefer to watch the video, here it is:
Enable CORS for OPTIONS request in HAProxy
First, add a new backend only for serving CORS in HAProxy:
backend cors_backend http-after-response set-header Access-Control-Allow-Origin "*" http-after-response set-header Access-Control-Allow-Headers "*" http-after-response set-header Access-Control-Max-Age "31536000" http-request return status 200
Now, in the frontend part, add a check for OPTIONS
request and direct that request to this backend:
frontend your_fe ... acl is_options method OPTIONS ... use_backend cors_backend if is_options # put your actual backend below this
Of course, in your actual backend, you need to set the CORS headers:
backend your_main_backend ... # START CORS http-response add-header Access-Control-Allow-Origin "*" http-response add-header Access-Control-Allow-Headers "*" http-response add-header Access-Control-Max-Age 3600 http-response add-header Access-Control-Allow-Methods "GET, DELETE, OPTIONS, POST, PUT, PATCH" # END CORS server w1 server:8080
And that’s all you need. Now you can work with your API CORS-free
The Complete configuration
Here are the complete configuration files:
- docker-compose.yml
version: '3.8' services: haproxy_license_server: container_name: haproxy_license_server image: haproxy:2.4.0 restart: always ports: - "7088:7088" - "8789:8788" volumes: - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
- haproxy.cfg
global stats timeout 30s defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 option forwardfor option http-server-close frontend ukata bind :8788 mode tcp acl is_options method OPTIONS use_backend cors_backend if is_options default_backend ukata_backend backend cors_backend http-after-response set-header Access-Control-Allow-Origin "*" http-after-response set-header Access-Control-Allow-Headers "*" http-after-response set-header Access-Control-Allow-Credentials "true" http-after-response set-header Access-Control-Allow-Methods "GET, DELETE, OPTIONS, POST, PUT, PATCH" http-after-response set-header Access-Control-Max-Age "31536000" http-request return status 200 backend ukata_backend mode http balance roundrobin # START CORS http-response add-header Access-Control-Allow-Origin "http://localhost:4200" http-response add-header Access-Control-Allow-Headers "*" http-response add-header Access-Control-Max-Age 3600 http-after-response set-header Access-Control-Allow-Credentials "true" http-response add-header Access-Control-Allow-Methods "GET, DELETE, OPTIONS, POST, PUT, PATCH" # END CORS # Don't set IP address of the server, use the hostname instead # set local-dev-1, 2 to your local ip address (192.168.x.x) server w1 192.168.100.6:8788 check
Caution
On a production server, you may need to replace the “*” with only the hosts you allowed (from your frontend, for example). In that case, you can replace * with your client URL (starts with http/https).
I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.
Hey, Thanks for this article, I am currently stuck with this problem, But I was unable to solve this:
I have a single frontend application with multiple backend, Can you publish your ha-proxy config file and replace the confidential data with a dump one, May be via Github , Thanks
CORS is conceived to protect your site from XSS attacks. That way you are completely giving up on this protection.
Agree. However, this is for development only. For production, you need to actually specify the allowed origin.
http-after-response doesn’t exists in HAPROXY configration