React 之仿酷我音乐 - docker + nginx + 宝塔面板部署前端项目并配置跨域

1,351 阅读6分钟

本文由 Loui 原创,如需转载,请先私信或评论。

介绍

本文将向你介绍使用 docker + nginx + 宝塔面板 部署高仿酷我音乐开源项目的具体步骤。

在开始前,请在你的服务器上安装好宝塔面板,如果没有安装也没关系,你只需要手动输入实现相同功能的命令即可。

如果你在阅读的过程中发现我没有写到位的地方,请在评论区指出,或者去阅读最底部列举一些的参考文章。

此外,我还写了另外一篇文章:《git + husky + webhook 优雅地实现前端项目自动部署》,希望也能帮到你。

步骤

在本地

克隆高仿酷我音乐开源项目到本地,使用 npm run build 进行构建,得到 dist 文件夹

在服务器

  1. 在服务器任意目录(这里以 www 目录为例)下,新建如下文件夹,并记住它们的绝对路径

    /www/kuwo-nginx/:存储nginx配置文件

    /www/kuwo-nginx/logs:存储nginx日志

    /www/kuwo-nginx/html:存储网站页面文件

    image.png

  2. 将本地 dist 文件夹里的内容上传到 kuwo-nginx/html 文件夹中

  3. 在 kuwo-nginx 文件夹下,提前新建 nginx 的配置文件:nginx.conf。输入如下内容,注意修改里面 root、server_name 两项的内容为你自己的

worker_processes  1;

# 打印 error 级别的错误日志到 logs/error.log
error_log  logs/error.log error;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    # 自定义一种日志的格式 customFormat
    log_format  customFormat  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';
    # 使用 customFormat 的格式打印访问日志到 logs/access.log
    access_log  logs/access.log  customFormat;
    

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        # 这里我们随便监听一个端口
        listen       5688;
        # 这里输入你要绑定的域名,有多个的话用空格隔开
        server_name  mock-kuwo.dynv6.net;

        location / {
            # 配置网站根目录
            root   /etc/nginx/html/;
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            #按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有的文件或文件夹都找不到,会进行一个内部重定向到最后一个参数,最后一个参数是回退URI且必须存在,否则会出现内部500错误。命名的location也可以使用在最后一个参数中。
            # 下面这样写可以将找不到对应文件的访问都让 index.html 处理,避免 spa 应用刷新出现 404 的错误,因为 spa 应用只有一个页面,路由跳转都是由 js 完成的
            try_files $uri $uri/ /index.html;
            index index.html index.htm;
            
        }
        
        #nginx反向代理,实现接口转发,^~ 表示以某个字符串开头的,优先匹配这里
        location ^~ /api/ {
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            proxy_set_header Referer https://www.kuwo.cn/;
            proxy_set_header Cookie $http_cookie;
            proxy_cookie_domain www.kuwo.cn mock-kuwo.dynv6.net;
            proxy_pass https://www.kuwo.cn/api/www/;
        }

        location ^~ /officialWebsite {
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            proxy_set_header Referer https://www.kuwo.cn/;
            proxy_set_header Cookie $http_cookie;
            proxy_cookie_domain www.kuwo.cn mock-kuwo.dynv6.net;
            proxy_pass https://www.kuwo.cn/;
        }
        
        location ^~ /officialWebsite/ {
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            proxy_set_header Referer https://www.kuwo.cn/;
            proxy_set_header Cookie $http_cookie;
            proxy_cookie_domain www.kuwo.cn mock-kuwo.dynv6.net;
            proxy_pass https://www.kuwo.cn/;
        }
    
        location ^~ /comment {
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            proxy_set_header Referer https://comment.kuwo.cn/;
            proxy_set_header Cookie $http_cookie;
            proxy_cookie_domain comment.kuwo.cn mock-kuwo.dynv6.net;
            proxy_pass https://comment.kuwo.cn/com.s;
        }
    
        location ^~ /playurl/ {
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            proxy_set_header Referer https://www.kuwo.cn/;
            proxy_set_header Cookie $http_cookie;
            proxy_cookie_domain www.kuwo.cn mock-kuwo.dynv6.net;
            proxy_pass https://www.kuwo.cn/api/v1/www/;
        }
    
        location ^~ /payType/ {
            add_header 'Access-Control-Allow-Origin' $http_origin;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            proxy_set_header Referer https://www.kuwo.cn/;
            proxy_set_header Cookie $http_cookie;
            proxy_cookie_domain www.kuwo.cn mock-kuwo.dynv6.net;
            proxy_pass https://www.kuwo.cn/openapi/v1/www/;
        }
        
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}

请注意,在上面的的配置文件中,我随便监听了一个 5688 端口,你也可以改成其他的,因为将来这个 nginx 要运行在 docker 里,而 dokcer 里的网络环境和宿主机是隔开的,实际访问的端口需要再通过配置 docker 进行端口映射。

  1. 进入宝塔面板 Docker 选项页,安装 Dokcer image.png

  2. 安装完成后,进入线上镜像页,找到 nginx 镜像,点击拉取 image.png

  3. 进入容器页,点击创建容器 image.png

  4. 选择通过命令创建,接着输入如下命令,请将命令中的几个文件夹地址改成你的地址

docker run --name kuwo-nginx -p 5688:5688 -v /www/kuwo-nginx/nginx.conf:/etc/nginx/nginx.conf -v /www/kuwo-nginx/logs:/etc/nginx/logs -v /www/kuwo-nginx/html/dist:/etc/nginx/html -d nginx:latest

下面是上方命令不同部分的解释:

  • --name kuwo-nginx:设置创建的容器名称为 kuwo-nginx
  • -v 宿主机的文件路径:容器的文件路径:挂载宿主机的文件(夹)到 docker 容器里
  • -p 80:5688:设置端口映射,冒号左边的为宿主机的端口,右边的为容器内的端口。由于默认情况下,浏览器直接访问 IP、域名时使用的是 80 端口,这里也映射到了宿主机的 80 端口,所以你的域名解析到服务器 IP 后直接访问即可打开页面,直接输入服务器 IP 访问也能直接打开页面。
  • -d nginx:latest:指定后台启动,并指定后台启动的镜像名称

完成之后,正常访问 IP 或域名即可打开项目网页

image.png

如果你的服务器之前已经运行了一个网站,80 端口已经被占用了,那么请将容器的端口映射到宿主机上其他没有没有被占用的端口,例如 -p 5688:5688,接着再使用 docker 外部的 nginx 或者其他服务器的反向代理功能,将域名的 80 端口解析过去,例如可以使用宝塔面板新建一个 PHP 项目,绑定上域名,接着反向代理到 http://localhost:5688 image.png

参考文章