Docker启动的Nginx如何解决浏览器跨域问题?

作者站长头像
站长
· 阅读数 6

Nginx如何解决跨域问题

问题简述:

docker启动的nginx,修改配置文件default.conf,允许跨域不生效。平台:MacOS M1pro

问题描述:

我使用Vue实现了一个前端项目,使用Nginx静态资源代理监听80端口,向本地后端服务http://localhost:9000/发送Get请求

// 跨域访问后端项目
axios.get("http://localhost:9000/hello")
    .then(function (response) {
      console.log(response)
    })

go语言实现的后端项目核心代码,启动服务监听9000端口

func handler(w http.ResponseWriter, r *http.Request) {
    _, err := fmt.Fprintf(w, "Hello, 第一条消息")
    if err != nil {
        return
    }
}

func main() {
    http.HandleFunc("/hello", handler)
    err1 := http.ListenAndServe(":9000", nil)
    if err1 != nil {
        return
    }

}

将Vue项目打包为dist,复制到docker容器的/usr/share/nginx/html目录中,配置文件为:

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;
    location / {
        #允许跨域请求的域,* 代表所有
        add_header 'Access-Control-Allow-Origin' *;
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

启动过程略过,可以发现跨域错误Docker启动的Nginx如何解决浏览器跨域问题?直接使用浏览器访问9000端口是正常的:Docker启动的Nginx如何解决浏览器跨域问题?

如何在Nginx解决跨域问题,我已经了解前端虚拟代理、后端允许跨域方法。本问题只讨论nginx如何允许跨域。已经尝试的方法如下,已确定修改配置文件后重启nginx。

方法一:

    #access_log  /var/log/nginx/host.access.log  main;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        #允许跨域请求的域,* 代表所有
        add_header 'Access-Control-Allow-Origin' *;
    }

方法二:

    location / {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Credentials' 'true'; 
        if ( $request_method = 'OPTIONS' ) { 
            return 200; 
        }
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

方法三:增加always

    location / {
        add_header Access-Control-Allow-Origin * always;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always; 
        if ( $request_method = 'OPTIONS' ) { 
            return 200; 
        }
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

网络上可以直接搜索到的方法基本都尝试过,求大佬解答,并进一步讨论相关理论(从Nginx实现方法角度)特别强调,本项目使用Docker启动容器,因此容器向localhost分发流量的域名为host.docker.internal

回复
1个回答
avatar
test
2024-06-23

假如我有一个网站 www.simple.com ,这个对应一个静态的html网站。还有一个API域名 api.simple.com ,这个对应后端的API接口。

假如我在www.simple.com这个网站内,去调用 api.simple.com 这个域名的接口,这个时候,在没有任何配置的情况下,两个域名不一致,浏览器就会提示跨域,阻止访问api.simple.com这个域名的接口访问。

浏览器怎么去验证是否跨域,当浏览器发现 不是同源的请求,就会发起一个 OPTIONS 请求给被访问的接口,只有接口返回了同意跨域 (Access-Control-Allow-Origin/Methods/Headers) ,浏览器才会放行这个跨域请求。

所以解决跨域的唯一方法,就是被访问的一方,设置响应头,允许被跨域访问。

你这里的配置文件,我看到都是在给 html 设置同意跨域,而不是在给接口设置同意跨域。


nginx 设置允许跨域,就是用add_header这个指令,添加允许跨域的请求头。跨域问题,应该和nginx是不是在容器内运行,没有任何关系,它只和接口的OPTIONS响应有关系,响应是允许那么就可以跨域,响应是不允许,那么就不可以跨域。


如果你要用nginx解决跨域,配置可能这两种会比较常见:(随手写的例子,不一定能跑,意思到了就行)第一种方式:

server {
    listen 80;
    server_name www.simple.com; # 用一个域名部署前端项目
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
server {
    listen 80;
    server_name api.simple.com;  #单独用一个api域名代理到后端,并设置允许跨域
    location / {
        proxy_pass http://127.0.0.1:8080; 
        add_header 'Access-Control-Allow-Origin' 'http://www.simple.com';  # 允许www.simple.com跨域
    }
}

第二种方式:

server {
    listen 80;
    server_name www.simple.com;    # 这里前端和后端api都使用同一个域名访问,就没有跨域的问题了。
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    location /api {
        proxy_pass http://127.0.0.1:8080; 
    }
}
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容