Qingquan-Li / blog

My Blog
https://Qingquan-Li.github.io/blog/
132 stars 16 forks source link

Bypass CORS #267

Open Qingquan-Li opened 6 months ago

Qingquan-Li commented 6 months ago

When you cannot configure the CORS (Cross-Origin Resource Sharing) on the backend (API server), you can "bypass" the CORS restriction using the proxy.

1. Bypass CORS with Nginx inside a Docker Container

1.1 Create a Dockerfile for Nginx

# Use the official NGINX image as a parent image
FROM nginx:alpine

# Remove the default nginx.conf
RUN rm /etc/nginx/conf.d/default.conf

# Copy the custom nginx.conf to the container
COPY nginx.conf /etc/nginx/conf.d

# Expose port 80 to the Docker host, so we can access it from the outside.
EXPOSE 80

1.2 Create an nginx.conf file (in the same directory as the Dockerfile)

server {
    listen 80;

    location /api {
        proxy_pass https://123.456.789.101:9222; # Your API server
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_ssl_verify off; # If you're using a self-signed certificate on the server
        # proxy_set_header Authorization "Bearer Your-Bearer-Token-Value"; # If you want to set auth header globally

        # CORS headers
        add_header 'Access-Control-Allow-Origin' 'http://localhost:5173' always; # Allow your frontend origin. Change the port as needed
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; # Adjust methods as needed
        add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range' always;
        if ($request_method = 'OPTIONS') {
            # Pre-flight request
            add_header 'Access-Control-Allow-Origin' 'http://localhost:5173'; # Change the port as needed
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept';
            add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range';
            add_header 'Access-Control-Max-Age' 1728000; # 20 days
            add_header 'Content-Type' 'text/plain; charset=UTF-8';
            add_header 'Content-Length' 0;
            return 204;
        }
    }
}

1.3 Build and Run the Docker Container

# cd path/to/Dockerfile

# Build the Docker image
docker build -t bypass-cors-with-nginx-proxy .

# Run your Docker container
# 8080:80 -> host:container
docker run  -p 8080:80 bypass-cors-with-nginx-proxy

This will start the NGINX container and listen on port 8080 of your host machine. Requests to http://localhost:8080/api will be proxied to https://123.456.789.101:9222/api.

1.4 Frontend Request

Example:

axios.get('http://localhost:8080/api/v1/get/submission?submissionId=1', {
  headers: {
    Accept: 'application/json',
    Authorization: 'Bearer Your-Bearer-Token-Value', // If any
  },
})

2. Bypass CORS with Vite

If you use Vite as your frontend tool, you can use Vite's built-in proxy feature to route your API requests through a proxy. This approach works during development (only).

Reference: https://vitejs.dev/config/server-options.html#server-proxy

2.1 Add a proxy configuration in vite.config.js

Assuming you're developing a React project with Vite:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  // Proxy any request from your local development server to /api/*
  // to https://123.456.789.101:9222/*
  server: {
    proxy: {
      '/api': {
        // Your API Server
        target: 'https://123.456.789.101:9222',
        // Required for CORS. Allow to use the same origin
        changeOrigin: true,
        // If your API is over HTTPS and you are using a self-signed certificate on the server
        secure: false,
        // Remove /api prefix before sending the request to the server. Use case: when the server doesn't expect /api prefix.
        // rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
})

2.2 Frontend Request

Example:

axios.get('api/v1/get/submission?submissionId=1', {
  headers: {
    Accept: 'application/json',
    Authorization: 'Bearer Your-Bearer-Token-Value', // If any
  },
})