首页 > 系统相关 >nginx配置解决跨域访问

nginx配置解决跨域访问

时间:2023-10-21 15:59:53浏览次数:42  
标签:http 跨域 header 访问 nginx api proxy

场景:前后的分离项目,前端vue框架,打包后放在Tomcat里访问,端口是8080,后端服务端口8058。访问前端项目时,调用后端接口报跨域。

后端环境

正常访问端口8058
image
经过nginx配置(文末具体展示)后,去除端口,如下:
image

前端开发环境

1. 配置开发和生产的环境变量

.env.development文件

# API服务路径
VITE_APP_BASE_URL = ""

.env.production文件

# API服务路径,注意没有端口号,是经过nginx处理后的后端服务地址
VITE_APP_BASE_URL = "http://192.168.1.4/"

2. vite.config.ts 文件配置开发代理

import { warpperEnv } from "./build";
import { UserConfigExport, ConfigEnv, loadEnv } from "vite";

/** 当前执行node命令时文件夹的地址(工作目录) */
const root: string = process.cwd();

export default ({ command, mode }: ConfigEnv): UserConfigExport => {
  const { VITE_CDN, VITE_PORT, VITE_COMPRESSION, VITE_PUBLIC_PATH } =
    warpperEnv(loadEnv(mode, root));
  return {
    base: VITE_PUBLIC_PATH,
    root,
    resolve: {
      alias
    },
    // 服务端渲染
    server: {
      // 是否开启 https
      https: false,
      // 端口号
      port: VITE_PORT,
      host: "0.0.0.0",
      // 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
      proxy: {
        "^/api": {
          target: "http://192.168.1.4:8058",
          changeOrigin: true,
          rewrite: path => path.replace(/^\/api/, "")
        }
      }
    },
    // 后面省略...
  }
};

3. http 文件封装 axios,使用环境变量配置的基础API路径

// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求地址
  baseURL: import.meta.env.VITE_APP_BASE_URL,
  // 请求超时时间
  timeout: 5000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  }
};

4. api 文件里使用示例

import { http } from "@/utils/http";

export type UserResult = {
  success: boolean;
  data: {
    username: string;
    roles: Array<string>;
    accessToken: string;
    refreshToken: string;
    expires: Date;
  };
};

/** 登录 */
export const getLogin = (data?: object) => {
  return http.request<UserResult>("post", "/api/login", { data });
};

5. 开发环境项目预览

由于使用了代理,所以不会有跨域的问题,如图:
image

前端生产环境

生产环境采用Tomcat,前端项目打包好后,放在Tomcat的 webapps/ROOT 目录下即可,如图:
image
启动Tomcat,双击 apache-tomcat-8.5.93/bin/ 目录下的 startup.bat,linux机器到 bin 目录下,运行 ./startup.sh
image
访问,Tomcat默认端口为8080,访问后台接口报跨域错误
image
nginx配置后,去除端口,访问正常
image

nginx配置

以上可以看出,nginx配置的目的,就是去除前后端的端口差异,从而解决跨域的问题。配置文件 nginx/conf/nginx.conf 修改如下:

server {
  listen       80;
  # IP/域名都可以
  server_name  http://192.168.1.4;
  #charset koi8-r;
  #access_log  logs/host.access.log  main;
  
  location / {
    root   html;
    index  index.html index.htm;
    proxy_pass http://192.168.1.4:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_connect_timeout 5;
  }
  
  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,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_pass http://192.168.1.4:8058/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_connect_timeout 5;
  }
}

疑问解答

1. 此示例项目,本地模拟的线上环境,操作系统 windows,后端服务 nodejs。换成 linux 系统或其他后端服务(如:SpringBoot 等)还适用吗,为什么?

答:同样适用。
因为跨域问题是浏览器为了安全保证,当你前端服务访问跨域资源时,被浏览器默认禁止了,所以和后端服务是什么,没有必然关系;所以解决问题的思路也是让我们的访问请求,达到浏览器的要求,即不跨域(同一域名/IP、端口、协议),那当然使用 nginx 就可以。

2. 前端请求里的代理里的 ^api,和nginx配置里的 ^~ /api/ 有什么关系?

答:有关系,但是不是你想象的关系。
首先我们要确认,你的实际的请求地址里,其实不包含 api 这段路径。如图:
image
开发环境加这个只是为了代理区分,因为你可能要请求多个不同域名的后端服务:我可以在 vite.config.ts 文件的 proxy 里再加一个以 ^/auth 开头的,导向其他域名的后端服务。
其次代码里也可以看到 rewrite: path => path.replace(/^\/api/, ""),所以实际的请求地址,最终是去掉了 api
那为什么nginx里要配置成 api 呢?
因为线上环境是没有运行代理的,也就是说 rewrite: path => path.replace(/^\/api/, "") 这一段是没有生效的,那你前端实际的请求地址就是 http://192.168.1.4/api/login,而真正的地址里没有 api 这一段,所以多出来的这一段,正好让nginx去代理,^~ /api/ 变成 http://192.168.1.4:8058/,从而使请求地址变成 http://192.168.1.4:8058/login

3. 接上,这两 api 虽然不是我想象的关系,但是事实上必须保持一致,有没有什么可以解耦的办法?

答:有。
nginx一般不会去随便改动,所以我们的解决办法优先放在前端,让前端去适配nginx。
参考 vite.config.ts 文件的代理地址替换,那我们在实际请求地址时,也可以做一个替换处理:在 http 文件里的请求拦截器中,判断是否生产环境,如果是,则替换 ^api 为nginx配置的开头路径即可。

4. 接上,vite.config.ts 可以配置多个代理,nginx也可以配置多个后端服务,但是 http 文件里的 axios 封装只有一个 baseURL

答:不是有拦截器吗。
env 环境配置里增加多个域名字段,假如以 auth 开头是另一个域名,那就在拦截器里使用条件判断,如果是 auth 开头,修改 config.baseURL 地址。
或者封装多个 axois?不建议,代码重复率又高了。

5. 既然nginx已经把 api 开头的都代理到了后端服务,那我前端就不能有 api 开头的路由?

答:可以。
看看访问路径,前端是哈希路由,有 # 号分隔的。如果是 history 路由呢,有试过的同学可以在评论区吱个声

标签:http,跨域,header,访问,nginx,api,proxy
From: https://www.cnblogs.com/weizwz/p/17778887.html

相关文章

  • CentOS 7 安装 Nginx
    CentOS7安装Nginx一、更新存储库包列表$sudoyum-yupdate-y是可选参数。表示安装软件过程中如果提示用户输入y进行确认安装的话,则进行自动确认。二、安装epel软件包问题:什么是epel?回答:epel-release仓库是由Fedora项目创建的,旨在为RHEL和CentOS用户提......
  • NGINX 安装 SSL 证书 - 开启 HTTPS 访问
    在NGINX上安装SSL证书-开启HTTPS访问一、在你开始之前请确保您已下载证书文件。没有证书?请从https://www.sslforfree.com上申请90天免费证书。下载证书后,您应该有一个包含以下证书文件的ZIP:certificate.crtca_bundle.crtprivate.key二、上传证书文件首先,......
  • 无法访问。你可能没有权限使用网络资源。请与这台服务器的管理员联系以查明你是否有
     无法访问。你可能没有权限使用网络资源。请与这台服务器的管理员联系以查明你是否有访问权限连到系统上的设备没有发挥作用弹出提示界面如下下: 解决办法,进入cmd--> gpedit.msc,改注册表:  记得重启电脑 ......
  • laravel:访问redis(10.27.0)
    一,相关文档:https://learnku.com/docs/laravel/10.x/redis/14887二,php代码1,配置.env使用默认的设置:REDIS_HOST=127.0.0.1REDIS_PASSWORD=nullREDIS_PORT=63792,controller中引用:12345678910111213141516171819202122232425<?ph......
  • laravel:部署到nginx服务器(10.27.0)
    一,相关文档:https://learnku.com/docs/laravel/10.x/deployment/14840二,配置nginx1,站点文件server{listen80;#listen[::]:80;server_namedig.lhdtest.com;root/webdata/site/dig/public;add_headerX-Frame-Options"SAMEORIGIN";a......
  • MySQL学习(6)单表访问方法
    什么是访问方法MySQL执行查询语句的方式称为访问方法(accessmethod)。单表的访问方法有哪些const通过主键或唯一二级索引列定位一条记录的方法叫const,这种方法要求主键列或者唯一二级索引列与一个常数进行等值比较时才有效。注意,使用唯一二级索引且搜索条件为ISNULL无效。例......
  • Nginx安装lua模块
    前提已安装完成Nginx安装LuaJITwgethttp://luajit.org/download/LuaJIT-2.0.5.tar.gztar-zxvf LuaJIT-2.0.5.tar.gzcdLuaJIT-2.0.5makeinstallPREFIX=/usr/local/LuaJITecho"exportLUAJIT_LIB=/usr/local/LuaJIT/lib">>/etc/profileecho"expor......
  • Nginx Lua修改返回值
    调试lua脚本ngx.log(ngx.ERR,"xxx")日志会打印到/usr/local/nginx/logs/error.log修改返回值时避免内容被截断增加header_filter_by_lua'ngx.header.content_length=nil';注释后只返回原接口长度3,即ok\n。lua脚本默认必须放在/usr/local/nginx目录下,否则会找不到。mod......
  • nginx首次安装sticky模块-cookie保持会话
    首次安装nginx:(下一篇文章是nginx添加sticky模块)yuminstall-ypcre*openssl*gccgcc-c++make--安装编译环境wgethttps://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/get/08a395c66e42.zip--下载sticky模块nginx-v--查看Nginx版本,因为要下载和yum安装nginx......
  • nginx添加sticky模块-cookie保持会话
    环境nginx1.8.0 centos6.X sticky:1.2.5 wgethttps://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/get/master.tar.gzcookie负载均衡相比iphash来比其中一个特点比较明显:内网nat用户的均衡。而iphash无法做到。yuminstallopenssl openssl-devel先停止ngi......