我们知道跨域在前端开发中是一个非常常见的问题,我们平时也有很多方法去解决他,比如说降域、cors、jsonp、postMessage等。还有一种很常用的方式是用nginx反代的方式去实现跨域,今天我们就来谈一谈关于使用nginx反代来实现跨域的问题。
我们都知道,跨域问题的产生是因为不同源的问题,那么,同源是指什么呢?同源,即域名、协议、端口都一样即同源。如果有一个不一样则不同源。而浏览器为了安全,对不同源的请求做了限制,即不允许发一个非同源的请求。这里需要划重点:浏览器为了安全。这个意思就是,这个行为是浏览器的行为,而不是你发一个不同源的请求就会被拦截。那么这个问题就好解决了,我们把请求发送到nginx上,在由nginx发送到目的服务器,目的服务器处理完毕后,同样把消息在发送给nginx,nginx在返回给前端。我们在服务器的层面上去处理跨域的问题,就不存在跨域的限制了。
如何在本地配置nginx这里我就不介绍了,如果不了解的同学可以先上网找一找相关的内容学习一下,下面我们先一步步实现。首先先用node在本地搭一个简单的服务器:
var http = require('http');
var hostName = '127.0.0.1';
var port = 8080;
var server = http.createServer(function(req, res) {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify('hello'));
});
server.listen(port, hostName, function() {
console.log(`服务器已启动: ${hostName}:${port}`);
})
这样,我们就在本地的8080端口起了一个简单的服务器,我们可以尝试一下:
下面我们再写一个简单的页面,然后用ajax去请求hello数据。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<script>
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
}
xhr.open("GET", "localhost:8080", true);
xhr.send();
script>
body>
html>
不出意外的,请求失败了:
这个报错就是典型的跨域问题,那么,我们下面想办法解决这个问题。
首先,我们要让这个请求变成同源的请求,即我们需要让他们的端口相同。
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8888; # 任意
server_name localhost;
location / {
proxy_pass http://localhost:5501/client.index.html;
}
}
}
这是nginx的配置文件,看不懂的同学不要紧,我们只需要关注核心部分,即server。listen表示我们的nginx是在端口8888上启动的,location /表示它会拦截localhost:8888这个请求,proxy_pass表示它会将这个请求转发到后面的url上去。最后的效果是什么呢?我们来看一下:
我们访问8888端口就可以访问到原来在5001端口上的网页,可是这里还是出现了跨域问题,因为他们的端口还是不一样,下面我们把ajax请求的地址改一下,改成同源请求。
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
}
xhr.open("GET", "api/getMessage", true);
xhr.send();
修改后的代码如上所示,此时我们肯定还是不能正常接受到请求的,因为我们在8888端口上根本没有写其他的代码,我们再修改一下nginx配置文件
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8888; # 任意
server_name localhost;
location / {
proxy_pass http://localhost:5501/client/index.html;
}
location /api/getMessage {
proxy_pass http://localhost:8080;
}
}
}
我们将/api/getMessage的请求转发到8080端口的服务器上,这样就能正常请求数据了。我们启动nginx,然后打开网页看看效果:
此时,我们已经正常请求到了数据,而我们的网页和api接口是在两个端口上的。所以这样,我们就利用nginx来实现了跨域的效果。
其实,在这里我们的网页、api接口、nginx分别在三个端口上。其实我们可以把nginx和网页放在一个端口上。那么我们为什么要这么做呢?因为为了更好的理解nginx是如何实现跨域的。只要在浏览器请求的url和自己的url是同源的,那么浏览器就不会对其作出限制。所以,我们将请求都转发到了nginx上,这样我们的各种请求都变成同源的了。至于真实的地址,就由nginx来进行转发,然后返回结果。好了,如果还有不理解的同学可以自己慢慢配一遍,相信你就能理解为什么nginx反代能实现跨域了。