一. 產(chǎn)生跨域的原因
1.瀏覽器限制
2.跨域
3.XHR(XMLHttpRequest)請求
二. 解決思路
解決跨域有多重括袒,在這里主要講用nginx解決跨域
1.JSONP
2.nginx代理
3.瀏覽器禁止檢查跨域
三. 下載安裝nginx
- 選擇其中一個版本下載列肢,再解壓即可使用
- 在nginx目錄下輸入nginx -v顺献,若出現(xiàn)版本號壤蚜,則安裝成功
四. nginx反向代理解決跨域(客戶端解決跨域)
1.我們使用jquery的ajax發(fā)送請求,node開啟后臺服務(wù)
前端代碼:
利用jQuery的ajax api發(fā)送請求
<button id="getOK">發(fā)送請求OK(客戶端解決跨域問題)</button>
<button id="getNO">發(fā)送請求NO(客戶端解決跨域問題)</button>
<script>
$(document).ready(function () {
$('#getOK').click(function () {
$.ajax({
url:'http://localhost:3000/ok',
success:function(res) {
console.log("success",res)
},
error:function(err) {
console.log('fail',err)
}
})
})
$('#getNO').click(function () {
$.ajax({
url:'http://localhost:3000/no',
success:function(res) {
console.log("success",res)
},
error:function(err) {
console.log('fail',err)
}
})
})
})
</script>
后端代碼:
利用node的express框架開啟服務(wù)肛响,并根據(jù)url返回json格式的數(shù)據(jù),
設(shè)置這么多接口的目的是為了后面匹配nginx的location配置的
const express = require('express')
const cookieParser = require('cookie-parser')
var app = express()
var router = express.Router()
router.get('/ok',function (req,res) {
res.json({
code:200,
msg:"isOK"
})
})
router.get('/ok/son',function (req,res) {
res.json({
code:200,
msg:"isOKSon"
})
})
router.get('/ok2',function (req,res) {
res.json({
code:200,
msg:"isOK2"
})
})
router.get('/no',function (req,res) {
res.json({
code:200,
msg:"isNO"
})
})
router.get('/no/son',function (req,res) {
res.json({
code:200,
msg:"isNOSON"
})
})
router.get('/no/son2',function (req,res) {
res.json({
code:200,
msg:"isNOSON2"
})
})
app.use(router)
app.use(cookieParser)
app.listen(3000,function () {
console.log('listen in 3000')
})
然后開啟node服務(wù)
現(xiàn)在可以測試下接口
可以看出郭膛,node服務(wù)成功開啟
現(xiàn)在可以嘗試不開啟nginx服務(wù)直接發(fā)送ajax請求會出現(xiàn)什么情況
(注意:發(fā)送ajax請求需要以服務(wù)器方式打開網(wǎng)頁闪檬,不能以文件形式)
如圖星著,在5500端口請求3000端口出現(xiàn)了跨域問題,這時候就可以開啟nginx服務(wù)并配置location進行解決
2.配置nginx進行反向代理解決跨域
反向代理的原理就是講前端的地址和后端的地址用nginx轉(zhuǎn)發(fā)到同一個地址下粗悯,如5500端口和3000端口都轉(zhuǎn)到3003端口下虚循,具體配置如下:
- 打開nginx目錄下的conf目錄里面nginx.conf
- 為了方便以后測試,我們將配置分離開來样傍,弄成多個文件
- 在nginx.conf的http對象的最后加上include ../vhost/test.conf;(注意要最后加上分號)
- 這樣就可以在test.conf下單獨配置了
具體的location配置規(guī)則如下:
server
{
listen 3003;
server_name localhost;
## = /表示精確匹配路徑為/的url横缔,真實訪問為http://localhost:5500
location = / {
proxy_pass http://localhost:5500;
}
## /no 表示以/no開頭的url,包括/no1,no/son衫哥,或者no/son/grandson
## 真實訪問為http://localhost:5500/no開頭的url
## 若 proxy_pass最后為/ 如http://localhost:3000/;匹配/no/son茎刚,則真實匹配為http://localhost:3000/son
location /no {
proxy_pass http://localhost:3000;
}
## /ok/表示精確匹配以ok開頭的url,/ok2是匹配不到的撤逢,/ok/son則可以
location /ok/ {
proxy_pass http://localhost:3000;
}
}
上面代碼的意思是將localhost:3003轉(zhuǎn)發(fā)為location:5500,也就是說現(xiàn)在訪問localhost:3003實際上是訪問location:5500,而訪問localhost:3003/no則是訪問localhost:3000,并以no開頭的url
- 現(xiàn)在我們可以開啟nginx服務(wù)了膛锭,在nginx目錄下使用start nginx即可開啟服務(wù)
- 每次修改配置都需要執(zhí)行nginx -s reload命令才能生效
現(xiàn)在修改前端代碼,將之前請求的接口的端口換為3003蚊荣,如下:
$('#getOK').click(function () {
$.ajax({
url:'http://localhost:3003/ok',
success:function(res) {
console.log("success",res)
},
error:function(err) {
console.log('fail',err)
}
})
})
在瀏覽器訪問的也不算location:5500,而是localhost:3003了初狰,再次發(fā)送請求也不會出現(xiàn)跨域問題了,因為他們都是同一個域了互例,這就是nginx反向代理
五. 后端配置nginx解決跨域(服務(wù)端解決跨域)
1. 依舊是ajax+node
這是前端代碼
$(document).ready(function () {
$('#get').click(function () {
$.ajax({
url:'http://localhost:3002/ok',
// 帶cookies的請求
xhrFields:{
withCredentials:true
},
success:function(res) {
console.log("success",res)
},
error:function(err) {
console.log('fail',err)
}
})
})
})
后端代碼同前面
還有nginx配置如下:
server
{
listen 3002;
server_name localhost;
location /ok {
proxy_pass http://localhost:3000;
# 指定允許跨域的方法奢入,*代表所有
add_header Access-Control-Allow-Methods *;
# 預(yù)檢命令的緩存,如果不緩存每次會發(fā)送兩次請求
add_header Access-Control-Max-Age 3600;
# 帶cookie請求需要加上這個字段敲霍,并設(shè)置為true
add_header Access-Control-Allow-Credentials true;
# 表示允許這個域跨域調(diào)用(客戶端發(fā)送請求的域名和端口)
# $http_origin動態(tài)獲取請求客戶端請求的域 不用*的原因是帶cookie的請求不支持*號
add_header Access-Control-Allow-Origin $http_origin;
# 表示請求頭的字段 動態(tài)獲取
add_header Access-Control-Allow-Headers
$http_access_control_request_headers;
# OPTIONS預(yù)檢命令俊马,預(yù)檢命令通過時才發(fā)送請求
# 檢查請求的類型是不是預(yù)檢命令
if ($request_method = OPTIONS){
return 200;
}
}
}
發(fā)送預(yù)檢命令的是非簡單請求丁存,具體可以看慕課網(wǎng)ajax跨域完全講解
實際上不是非簡單請求的且不帶cookie只需2個字段即可解決跨域
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Origin $http_origin;
- 具體效果如下圖:
這時只需改ajax請求的端口接口肩杈,無需修改前端服務(wù)器的地址