nginx反向代理解决ajax跨域问题

跨域问题,是前端同学遇到和服务器交换数据最常见的问题。下面就说一下如何解决跨域问题。
个人认为,通过 nginx 反向代理解决跨域是最为简单和方便,并且针对:测试过程为跨域,线上为同域的场景

1. 什么是跨域

跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对 javascript 施加的安全限制。

所谓同源是指,域名,协议,端口相同。浏览器执行 javascript 脚本时,会检查这个脚本属于那个页面,如果不是同源页面,就不会被执行。
同源策略的目的,是防止黑客做一些做奸犯科的勾当。比如说,如果一个银行的一个应用允许用户上传网页,如果没有同源策略,黑客可以编写一个登陆表单提交到自己的服务器上,得到一个看上去相当高大上的页面。黑客把这个页面通过邮件等发给用户,用户误认为这是某银行的主网页进行登陆,就会泄露自己的用户数据。而因为浏览器的同源策略,黑客无法收到表单数据。

2. 常见的解决跨域的方法

  1. 使用 iFrame 访问另一个域。 然后再从另一个页面读取 iFrame 的内容。jquery 等有一些封装。
  1. jsonp。需要服务器支持。使用 script src 动态得到一段 javascript 代码。是回调页面上的 js 函数,参数是一个 json 对象。jquery 有封装。
  2. 设置 http 头,Access-Control-Allow-Origin: // 或者一个具体的 origin
  3. 服务器代理。将某个请求代理到服务器地址

3. nginx 反向代理

以上的方法,都会造成测试代码和正式代码的不一致,导致重复和多余的工作量,而且测试也不方便。
例如:用 iframe,已经过时的使用, jsonp 需要服务其支持,将返回封装在 CALLBACK 里面, http 修改 Access 需要服务器支持修改。
那么: 用 nginx 反向代理实现跨域,是最简单的跨域方式。只需要修改 nginx 的配置即可解决跨域问题,支持所有浏览器,支持 session,不需要修改任何代码,并且不会影响服务器性能。

我们只需要配置 nginx,在一个服务器上配置多个前缀来转发 http/https 请求到多个真实的服务器即可。这样,这个服务器上所有 url 都是相同的域名、协议和端口。因此,对于浏览器来说,这些 url 都是同源的,没有跨域限制。而实际上,这些 url 实际上由物理服务器提供服务。这些服务器内的 javascript 可以跨域调用所有这些服务器上的 url。

4. 配置过程

打开 nginx.conf 的配置文件找到 server 项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server {
listen 8080; #服务监听的端口
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root /work/; #项目目录
index index.html index.htm;
}
#反向代理开始
#拦截所有/ios/的请求并将以ws_开头的请求代理到 http://192.168.255.140:80/
location ^~/ios/{
rewrite ^ws* /$1 break; #代理的规则(正则表达式)
include uwsgi_params;
proxy_pass http://192.168.255.140:80/; #要代理到的url
}

}

5. 平滑重启

1
通过 nginx -s reload 来重启nginx

6. nginx 的正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1、正则表达式匹配
~ 为区分大小写的匹配。
~* 不区分大小写的匹配(匹配firefox的正则同时匹配FireFox)。
!~ 不匹配的
!~* 不匹配的
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束

* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n
{n,} 重复n次或更多次
{n,m} 重复n到m次
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

捕获 (exp) 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言 (?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
注释 (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读


2、文件及目录匹配
-f和!-f用来判断是否存在文件
-d和!-d用来判断是否存在目录
-e和!-e用来判断是否存在文件或目录
-x和!-x用来判断文件是否可执行

例如:

1
2
3
4
5
6
location = /
#匹配任何查询,因为所有请求都已 / 开头。但是正则表达式规则和长的块规则将被优先和查询匹配
location ^~ /images/ {
# 匹配任何已/images/开头的任何查询并且停止搜索。任何正则表达式将不会被测试。
location ~* .(gif|jpg|jpeg)$ {
# 匹配任何已.gif、.jpg 或 .jpeg 结尾的请求