nginxproxymanager dnspod证书_nginx 隐藏真实的url


上篇 JSONP 的文章里提到过利用 Nginx 也可以解决跨域问题。趁着自己以前没有接触过 Nginx,熟悉了一下,顺带写了一个非常非常简单的 demo 实验下。

正向代理和反向代理

提到代理,肯定要说一下这两个的区别。

举个正向代理的例子:我打球累了走不动了,找看球的小朋友帮我去旁边的商店买瓶水。商店老板是不知道到底是谁需要喝水的,隐藏了客户端。当然,小朋友可以告诉老板就是那个打球像蔡徐坤的人要喝水。还有,VPN 就是正向代理。

反向代理的例子:我打球累了,找看球的小朋友要瓶水喝(当然我肯定会给钱的:D)。我不需要知道小朋友的水是从旁边的商店还是两公里外的超市买的。隐藏了服务端。还有,我们连好了 VPN 访问谷歌的时候,浏览的那些页面,我们是不会知道具体是哪台服务器的资源。

具体步骤

  • 服务接口

既然请求,肯定需要先写一个服务接口,我们用 node 起一个服务:


// index.js
const http = require('http');
const fs = require('fs');
const url = require('url');

const server = http.createServer(function (req, res) {
  if (req.url === '/favicon.ico') {
    return;
  }
  const parseUrl = url.parse(req.url, true);
  console.log('parseUrl', parseUrl.pathname)
  if (parseUrl.pathname === '/api/getList') {
    const list = {'a': 1, 'b': 2}
    res.writeHead(200, {'content-Type':'text/html;charset=UTF-8'})  
    res.end(JSON.stringify(list))
  }else {
    res.write(`
    port: 666
  `)
    res.end()
  }
});
server.listen(666, function () {
  console.log('server is starting on port 666');
});


我们来访问一下,可以拿到数据了。


nginxproxymanager dnspod证书_nginx 跨域_02


  • 测试页面

然后,我们写一个简单的 ajax 请求页面。你可以本地用http-server启动访问下,可以发现请求跨域了:


<html>
<head>
  <title></title>
</head>
<body>
  <button onclick="sendAjax()">sendAjax</button>
<script type="text/javascript">
  var sendAjax = () => {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', 'http://localhost:666/api/getList', true);
      xhr.send();
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState == 4 && xhr.status == 200) {
          console.log(xhr.responseText);
        }
      };
  }
</script>
</body>
</html>


nginxproxymanager dnspod证书_nginx 跨域_03


  • 安装 Nginx

这个时候,你可以通过设置响应头来允许跨域。或者用 Nginx 来解决这个问题了。首先肯定需要安装 Nginx。这个按照对应的平台安装就行了。


brew update
brew install nginx
nginx
nginx -s reload // 重启


  • 配置

然后我们配置一下代理,这个意思就是我们请求中有 api 这样的就会代理到 http://127.0.0.1:666,所以我们只要访问 http://localhost:9999/api/getList 这个不跨域的接口,然后就会由服务器反向代理到 http://localhost:666/api/getList。


listen       9999;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        }
        location /api/ {
            proxy_pass http://127.0.0.1:666;
        }


配置好之后我们需要重启一下 Nginx 服务。注意一点,重启时可能会报这么一个错误:


nginx: [error] open() "/usr/local/var/run/nginx.pid" failed (2: No such file or directory)


这是 sudo nginx -s stop 这个命令会删除 pid 文件,可以执行 sudo nginx 重新添加这个文件。

  • 测试结果

这个时候,我们不用绝对地址了,我们把ajax请求里面的接口换成相对地址:


// xhr.open('GET', 'http://localhost:666/api/getList', true);
xhr.open('GET', '/api/getList', true);


nginxproxymanager dnspod证书_nginx 反向代理跨域访问配置_04


美滋滋,这就不跨域了呢。

当然,还可以更加真实一点,我们随便用一个域名测试一下。Nginx 重新配置下:


listen       80;
        server_name  yumingtest;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        }
        location /api/ {
            proxy_pass http://127.0.0.1:666;
        }


然后在 hosts 文件里面添加这条:127.0.0.1 yumingtest.com,重启下 Nginx。


nginxproxymanager dnspod证书_nginx跨域_05


这下是不是更加真实了。关于hosts 文件的作用,就是我们输入域名不是要需要经过DNS解析IP嘛,这个里面就存了一些。首先自动从 Hosts 文件中寻找对应的 IP 地址,一旦找到,系统会立即打开对应网页,如果没有找到, 则系统再会将网址提交 DNS 域名解析服务器进行 IP 地址的解析。

还有一个问题,关于 HTTP 502 状态码,我是把接口服务停了,于是就报 502了。


nginxproxymanager dnspod证书_nginx跨域_06


也不一定是网上说的什么连接超时 我们向服务器发送请求 由于服务器当前链接太多,导致服务器方面无法给于正常的响应,产生此类报错那样。

(完)

2019.11.30 补充

上面 Hosts 文件那里说错了,输入域名后并不是先自动从 Hosts 文件中寻找对应的 IP 地址。而是浏览器先从浏览器的dns缓存中找,找不到再去 hosts文件中找 :)