Nginx 解决跨域

article/2025/9/19 10:29:37

项目准备

前端网站地址:http://localhost:8080

服务端网址:http://localhost:8081

确认服务端是没有处理跨域的,先用postman测试服务端接口是正常的

在这里插入图片描述

当前端网站8080去访问服务端接口时,就产生了跨域问题,那么如何解决?接下来我把跨域遇到的各种情况都列举出来并通过nginx代理的方式解决

跨域主要涉及4个响应头:

  1. Access-Control-Allow-Origin 用于设置允许跨域请求源地址 (预检请求和正式请求在跨域时候都会验证)

  2. Access-Control-Allow-Headers 跨域允许携带的特殊头信息字段 (只在预检请求验证)

  3. Access-Control-Allow-Methods 跨域允许的请求方法或者说HTTP动词 (只在预检请求验证)

  4. Access-Control-Allow-Credentials 是否允许跨域使用cookies,如果要跨域使用cookies,可以添加上此请求响应头,值设为true(设置或者不设置,都不会影响请求发送,只会影响在跨域时候是否要携带cookies,但是如果设置,预检请求和正式请求都需要设置)。不过不建议跨域使用(项目中用到过,不过不稳定,有些浏览器带不过去),除非必要,因为有很多方案可以代替。

预检请求: 当发生跨域条件时候,览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。如下图

图片

开始动手模拟

Nginx代理端口:22222 ,配置如下

server {listen       22222;server_name  localhost;location  / {proxy_pass  http://localhost:8081;}
}

测试代理是否成功,通过Nginx代理端口2222再次访问接口,可以看到如下图通过代理后接口也是能正常访问

图片

接下来开始用前端网站8080访问Nginx代理后的接口地址,报错情况如下↓↓↓

情况1:

Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

图片

通过错误信息可以很清晰的定位到错误(注意看标红部分)priflight说明是个预请求,CORS 机制跨域会首先进行 preflight(一个 OPTIONS 请求), 该请求成功后才会发送真正的请求。这一设计旨在确保服务器对 CORS 标准知情,以保护不支持 CORS 的旧服务器

通过错误信息,我们可以得到是预检请求的请求响应头缺少了Access-Control-Allow-Origin,错哪里,我们改哪里就好了。修改Nginx配置信息如下(红色部分为添加部分),缺什么就补什么,很简单明了

server {listen       22222;server_name  localhost;location  / {add_header Access-Control-Allow-Origin 'http://localhost:8080';proxy_pass  http://localhost:8081;}
}

以为能解决后,发现还是报了同样的问题

图片

不过我们的配置没什么问题,问题在Nginx,下图链接http://nginx.org/en/docs/http/ngx_http_headers_module.html

图片

add_header 指令用于添加返回头字段,当且仅当状态码为图中列出的那些时有效。如果想要每次响应信息都携带头字段信息,需要在最后添加always(经我测试,只有Access-Control-Allow-Origin这个头信息需要加always,其他的不加always也会携带回来)

server {listen       22222;server_name  localhost;location  / {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;proxy_pass  http://localhost:8081;}
}

修改了配置后,发现生效了,当然不是跨域就解决了,是上面这个问题已经解决了,因为报错内容已经变了。

情况2:

Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

图片

通过报错信息提示可以得知,是跨域浏览器默认行为的预请求(option请求)没有收到ok状态码,此时再修改配置文件,当请求为option请求时候,给浏览器返回一个状态码(一般是204)

server {listen       22222;server_name  localhost;location  / {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;if ($request_method = 'OPTIONS') {return 204;}proxy_pass  http://localhost:8081;}
}

当配置完后,发现报错信息变了

情况3:

Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

图片

意思就是预请求响应头Access-Control-Allow-Headers中缺少头信息authorization(各种情况会不一样,在发生跨域后,在自定义添加的头信息是不允许的,需要添加到请求响应头Access-Control-Allow-Headers中,以便浏览器知道此头信息的携带是服务器承认合法的,我这里携带的是authorization,其他的可能是token之类的,缺什么加什么),知道了问题所在,然后修改配置文件,添加对应缺少的部分,再试试

server {listen       22222;server_name  localhost;location  / {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Headers 'authorization'; #为什么写在if里面而不是接着Access-Control-Allow-Origin往下写?因为这里只有预检请求才会检查return 204;}proxy_pass http://localhost:8081;
}
}

此时发现报错问题又回到了情况1

图片

经测试验证,只要if ($request_method = 'OPTIONS') 里面写了 add_header ,当为预检请求时外部配置的都会失效,为什么?↓↓。

官方文档是这样说的:

There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.

意思就是当前层级无 add_header 指令时,则继承上一层级的add_header。相反的若当前层级有了add_header,就应该无法继承上一层的add_header。

图片

配置修改如下:

server {listen       22222;server_name  localhost;location  / {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:8080';add_header Access-Control-Allow-Headers 'authorization';return 204;}proxy_pass  http://localhost:8081;}
}

此时改完发现跨域问题已经解决了,

图片

不过以上虽然解决了跨域问题,但是考虑后期可能Nginx版本更新,不知道这个规则会不会被修改,考虑到这样的写法可能会携带上两个 Access-Control-Allow-Origin ,这种情况也是不允许的,下面会说到。所以配置适当修改如下:

server {listen       22222;server_name  localhost;location  / {if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:8080';add_header Access-Control-Allow-Headers 'authorization';return 204;}if ($request_method != 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;}proxy_pass  http://localhost:8081;}
}

情况4:

比较早期的API可能只用到了POST和GET请求,而Access-Control-Allow-Methods这个请求响应头跨域默认只支持POST和GET,当出现其他请求类型时候,同样会出现跨域异常。

比如,我这里将请求的API接口请求方式从原来的GET改成PUT,在发起一次试试。在控制台上会抛出错误:

Access to XMLHttpRequest at 'http://localhost:22222/api/Login/TestGet' from origin 'http://localhost:8080' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.

图片

报错内容也讲的很清楚,在这个预请求中,PUT方法是不允许在跨域中使用的,我们需要改下Access-Control-Allow-Methods的配置(缺什么加上么,这里我只加了PUT,可以自己加全一点),让浏览器知道服务端是允许的

server {listen 22222;server_name localhost;location / {if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:8080';add_header Access-Control-Allow-Headers 'content-type,authorization';add_header Access-Control-Allow-Methods 'PUT';#为这么只加在这个if中,不再下面的if也加上?因为这里只有预检请求会校验,当然你加上也没事。return 204;}if ($request_method != 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;}proxy_pass http://localhost:8081;}
}

?这里注意一下,改成PUT类型后,Access-Control-Allow-Headers请求响应头又会自动校验content-type这个请求头,和情况3是一样的,缺啥补啥就行了。如果不加上content-type,则会报如下错误。(想简单的话,Access-Control-Allow-Headers和Access-Control-Allow-Methods可以设置为 * ,表示全都匹配。但是Access-Control-Allow-Origin就不建议设置成 * 了,为了安全考虑,限制域名是很有必要的。)

图片

都加上后,问题就解决了,这里报405是我服务端这个接口只开放了GET,没有开放PUT,而此刻我将此接口用PUT方法去请求,所以接口会返回这个状态码。

图片

情况5:

后端处理了跨域,就不需要自己在处理了(这里吐槽下,某些后端工程师自己改服务端代码解决跨域,但是又不理解其中原理,网上随便找段代码黏贴,导致响应信息可能处理不完全,如method没添加全,headers没加到点上,自己用的那个可能复制过来的并不包含实际项目所用到的,没有添加options请求返回状态码等,导致Nginx再用通用的配置就会可能报以下异常)

Access to XMLHttpRequest at 'http://localhost:22222/api/Login/TestGet' from origin 'http://localhost:8080' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:8080', but only one is allowed.

在这里插入图片描述

意思就是此刻Access-Control-Allow-Origin请求响应头返回了多个,而只允许有一个,这种情况当然修改配置去掉Access-Control-Allow-Origin这个配置就可以了,不过遇到这种情况,建议Nginx配置和服务端自己解决跨域只选其一。(这里注意如果按我上面的写法,if $request_method = ‘OPTIONS’ 这个里面的Access-Control-Allow-Origin可不能删除,删除!='OPTIONS’里面的就好了,因为这里如果是预检请求直接就ruturn了,请求不会再转发到59200服务,如果也删除了,就会报和情况1一样的错误。所以为什么说要不服务端代码层面解决跨域,要不就Nginx代理解决,不要混着搞,不然不明白原理的人,网上找一段代码贴就很可能解决不了问题)

↓ ↓ ↓ ↓ ↓


server {listen       22222;server_name  localhost;location  / {if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:8080';add_header Access-Control-Allow-Headers '*';add_header Access-Control-Allow-Methods '*';add_header Access-Control-Allow-Credentials 'true';return 204;}if ($request_method != 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;add_header Access-Control-Allow-Credentials 'true';}proxy_pass  http://localhost:8081;}
}

或者:


server {listen       22222;server_name  localhost;location  / {add_header Access-Control-Allow-Origin 'http://localhost:8080' always;add_header Access-Control-Allow-Headers '*';add_header Access-Control-Allow-Methods '*';add_header Access-Control-Allow-Credentials 'true';if ($request_method = 'OPTIONS') {return 204;}proxy_pass  http://localhost:59200;}
}

http://chatgpt.dhexx.cn/article/Rd3b96Qy.shtml

相关文章

1 Nginx跨域配置

跨域问题在之前的单体架构开发中,其实是比较少见的问题,除非是需要接入第三方SDK时,才需要处理此问题。但随着现在前后端分离、分布式架构的流行,跨域问题也成为了每个Java开发必须要懂得解决的一个问题。 跨域问题产生的原因 产…

Nginx跨域配置

随着越来越多的项目走向了前后端分离,前端服务,需要访问到不同的后端地址,经常遇到跨域问题。本文主要介绍使用Nginx解决跨域问题。 1.什么是跨域 由于浏览器的同源策略,用来限制从一个源加载的文档或脚本与来自另一个源的资源进…

flyai中的dataset对象

Help on Dataset in module flyai.dataset object:class Dataset(builtins.object) | Methods defined here: | | __init__(self, epochs5, batch32, val_batch32) | :param epochs: 训练的轮次,最大不超过100 | :param batch: 训练的批次大小&#xff…

FlyAI资讯:Uber正式开源分布式机器学习平台:Fiber

摘要:在过去的几年中,计算机不断增强的处理能力推动了机器学习的进步。算法越来越多地利用并行性,并依赖分布式训练来处理大量数据。然而,随之而来的是增加数据和训练的需求,这对管理和利用大规模计算资源的软件提出了…

FlyAI小课堂:Python机器学习笔记:Logistic Regression

Logistic回归公式推导和代码实现 1,引言 logistic回归是机器学习中最常用最经典的分类方法之一,有人称之为逻辑回归或者逻辑斯蒂回归。虽然他称为回归模型,但是却处理的是分类问题,这主要是因为它的本质是一个线性模型加上一个映…

FlyAI竞赛:图片颜值打分趣味赛

人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,支持算法能力变现以及快速的…

FlyAI小课堂:Tensorflow-分布式训练

人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,支持算法能力变现以及快速的…

FlyAI小课堂:【文本分类-中文】textRNN

摘要: 随着深度学习的快速发展,人们创建了一整套神经网络结构来解决各种各样的任务和问题。在英文分类基础上,中文文本分类的处理也同样重要... 人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛&#x…

FlyAI小课堂:【文本分类-中文】textCNN

摘要: 随着深度学习的快速发展,人们创建了一整套神经网络结构来解决各种各样的任务和问题。在英文分类基础上,中文文本分类的处理也同样重要... 人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛&#x…

FlyAI人工智能社区参赛指南—用户体验版

Fly-AI竞赛服务平台 flyai.com 在开始学习之前推荐大家可以多在 FlyAI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,支持算法能力变现以…

FlyAI资讯:GPT-3的威力,助力AI领域

摘要:大概一个月之前,史上最巨无霸NLP模型GPT-3问世。当时它向世界展示的能力是,“不仅会写短文,而且写出来的作文挺逼真的,几乎可以骗过人类,可以说几乎通过了图灵测试。”可能是因为它的前一代模型GPT-2也…

FlyAI赛题预告:时间序列初学者指南

近期,FlyAI服务竞赛平台将上线时间序列相关赛题,看到此文的童鞋们可以多多关注下;推荐大家可以多在FlyAI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。…

FlyAI资讯:人工智能的前世今生

摘要: 现代电子产品和设备在诸如通信 、娱乐 、安全和医疗保健等许多方面改善了我们的生活质量 ,这主要是因为现代微电子技术的发展极大地改变了人们的日常工作和互动方式。在过去几十年中,摩尔定律一直是通过不断缩小芯 … 人工智能学习离不开实践的验…

FlyAI小课堂:Tensorflow基操

人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,支持算法能力变现以及快速的…

FlyAI资讯:台积电布局新存储技术

摘要:近年来,在人工智能(AI)、5G等推动下,以MRAM(磁阻式随机存取存储器)、铁电随机存取存储器 (FRAM)、相变随机存取存储器(PRAM),以及可变电阻式随机存取存储…

强烈推荐!FlyAI机器学习数据竞赛启动,丰厚奖金等你来拿

FlyAI 数据竞赛平台 FlyAI 是隶属于北京智能工场科技有限公司旗下,为AI开发者 (深度学习)提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,样例所使用开发框架涉及TensorFlow、Keras、PyTorch. 支持…

FlyAI竞赛服务平台赛题上新——手写英文字体识别(名企内推)

人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,支持算法能力变现以及快速的…

万元大奖,FlyAI算法新赛事,心理卡牌目标检测

本文转自竞赛社区FlyAI最新上线算法赛。 “心理卡牌目标检测算法赛”由测测星座与趣鸭心理联合发起的线上竞赛项目。2020年新冠肺炎疫情打破了我们平静的生活,影响了我们的身体健康和精神健康。在国家发布的《“健康中国2030”规划纲要》中也提到,要加大…

百万现金奖励,FlyAI实时竞赛等你来战

点击我爱计算机视觉标星,更快获取CVML新技术 这是一种新的算法竞赛方式! FlyAI是一个为算法工程师提供(深度学习)项目竞赛并支持GPU离线训练的网站。目前每周更新两个以上现金奖励的竞赛项目。项目涉及领域包括图像识别/分类/检测…

使用FlyAI进行科学数据竞赛

转自百度经验 https://jingyan.baidu.com/article/acf728fd9c3e6af8e510a392.html 工具/原料 python3 Windows命令行(mac/Linux都可运行,此经验以Windows为例) 百度经验:jingyan.baidu.com 注册账号 1 使用浏览器打开 www.flyai.com,并点击注…