欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前后端分離和跨域問題的詳細解決方案(CORS的原理)

 更新時間:2023年02月15日 11:35:25   作者:Renling【PHP】  
前后端跨域問題由瀏覽器同源策略而來,下面這篇文章主要給大家介紹了關于前后端分離和跨域問題的詳細解決方案,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

前后端分離

前后端分離的好處

  1. 最大的好處就是前端JS可以做很大部分的數(shù)據(jù)處理工作,對服務器的壓力減小到最小。
  2. 后臺錯誤不會直接反映到前臺,錯誤接秒較為友好。
  3. 由于后臺是很難去探知前臺頁面的分布情況,而這又是JS的強項,而JS又是無法獨立和服務器進行通訊的。所以單單用后臺去控制整體頁面,又或者只靠JS完成效果,都會難度加大,前后臺各盡其職可以最大程度的減少開發(fā)難度。

個人理解上存在兩種解釋

  • 第一種只是單純的前后端分離,實在物理層面上的,將View層的任務分配給前端,Controller和Model層給后端,這就存在一個問題,就是后端的同事需要去關注前端的展示邏輯、而前端只要存在變化,后端的數(shù)據(jù)處理需要做相應的改變。
  • 第二種是基于職責層面上的分離,將View和Controller層分配的前端,后端只處理Model和業(yè)務處理,這就需要Controller使用Node.js,M-V-C對應的是JAVA/PHP-JAVASCRIPT、HTML、CSS-Node.js。

跨域問題存在的原因

隨著前后端分離技術的越來越盛行,跨域問題也逐漸凸顯了出來??缬騿栴}的根本原因:因為瀏覽器收到同源策略的限制,當前域名的js只能讀取同域下的窗口屬性。什么叫做同源策略?就是不同的域名, 不同端口, 不同的協(xié)議不允許共享資源的,保障瀏覽器安全。同源策略是針對瀏覽器設置的門檻。如果繞過瀏覽就能實現(xiàn)跨域,所以說早期的跨域都是打著安全路數(shù)的擦邊球,都可以認為是 hack 處理。這一段是我從別的地方cp過來的,大家將就著看吧。

這里要注意的是,只有訪問類型為xhr(XMLHttpRequest)的才會出現(xiàn)跨域。

跨域問題的解決方案

  • 修改瀏覽器的設置
  • 修改請求的方式:jsonp
  • CORS

修改瀏覽器配置解決跨域

以Google Chrome為例,瀏覽器以

"C:\ProgramFiles(x86)\Google\Chrome\Application\chrome.exe"
    --disable-web-security--user-data-dir

中模式打開,右鍵點擊瀏覽器快捷方式,在目標中輸入上述代碼即可解決(不推薦)。

使用jsonp解決跨域

JQuery中的正常AJAX請求代碼片段

$("#demo1").click(function(){
    $.ajax({
        url : 'http://www.tpadmin.top/Index/Test/crossDomain',
        data : {},
        type : 'get',
        success : function (res) {
            //No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1' is therefore not allowed access. 在執(zhí)行時候報出的錯誤,這代表了跨域錯誤
            alert(res);
        }
    });
});?

 JQuery中的使用JSONP的AJAX請求代碼:

$("#demo2").click(function(){
    $.ajax({
        url : 'http://www.tpadmin.top/Index/Test/crossDomain',
        data : {},
        type : 'get',
        dataType : 'jsonp', 
        success : function (res) {
            alert(res);
        }
    });
});

這時候我們看到 請求的網(wǎng)址自動變成了

http://www.tpadmin.top/Index/Test/crossDomain?callback=jQuery331015214102388989237_1534993962395&_=1534993962396

這是為什么呢?原來由于跨域訪問的只限制xhr類型的請求(上文中已經(jīng)說了),所以js中就利用了這一特點,讓服務端不在返回的是一個JSON格式的數(shù)據(jù),而是返回一段JS代碼,將JSON的數(shù)據(jù)以參數(shù)的形式傳遞到這個函數(shù)中,而函數(shù)的名稱就是callback參數(shù)的值,所以我們還需要修改服務端的代碼,代碼如下:

<?php
    $callback = isset($_GET['callback'])?$_GET['callback']:'';
    if (!empty($callback)) {
        $arr = ['code' => 200, 'name' => 'cui'];
        $data = json_encode($arr);
        exit($callback . '(' . $data . ')');
    }
?>

OK,現(xiàn)在問題解決了,但是JSONP存在著諸多限制,下面將列出兩個個我知道的:

JSONP只支持GET請求,什么?你要提交表單,sorry,此路不通它只支持跨域HTTP請求

雖然只有兩個,但是讓很多人不得不放棄它,所以出現(xiàn)了下面的解決辦法。

CORS解決跨域 

回歸問題本質,跨域問題為什么會產(chǎn)生,上面已經(jīng)說了,是由于瀏覽器的限制,那么在執(zhí)行過程中有什么不同,下面兩張度分析一下(主要看請求頭的部分):

這是非跨域請求

這是跨域請求

這時我們發(fā)現(xiàn)跨域訪問的請求頭中存在Origin的字段,用來記錄當前的訪問域名,我們可以再服務端增加一個響應頭Access-Control-Allow-Origin來告訴瀏覽器我們支持它獲取就可以了,代碼實現(xiàn):

<?php
header('Access-Control-Allow-Origin:http://127.0.0.1');
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

那如果我有多個域名進行跨域訪問呢

<?php
$requestHeader = getallheaders();
$origin = isset($requestHeader['Origin'])?$requestHeader['Origin']:'';
switch ($origin) {
    case 'http://127.0.0.1':
        header('Access-Control-Allow-Origin:http://127.0.0.1');
        break;
    case 'http://localhost':
        header('Access-Control-Allow-Origin:http://localhost');
        break;
    default:
        break;
}
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
//注意,不支持下面這種寫法
//header('Access-Control-Allow-Origin:http://localhost,http://127.0.0.1');
?>

或者直接寫成(很不安全,不推薦這么寫)

<?php
header('Access-Control-Allow-Origin:*');
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

到這里,其實已經(jīng)結束了,但還有一些其他的特殊情況

  • 請求方法不是GET、HEAD、POST
  • 請求頭中存在自定義頭
  • Content-Type不是text/plain、multipart/form-data、application/x-www-form-urlencoded
  • 希望獲取到服務端的Cookie

為了應對種種限制,我們再來看一段代碼

$("#demo1").click(function(){
    $.ajax({
        url : 'http://cui.tpadmin.top/crossDomain.php',
        data : {},
        type : 'PUT',
        contentType : 'application/json',
        header: {
            token:'asdfgqwerttyyazxcvbvb'
        },
        success : function (res) {
            alert(res);
        }
    });
});

雖然我們在服務端加入了Access-Control-Allow-Origin響應頭,但是如果出現(xiàn)上面所說的情況時,我們需要做一些特殊的設置,修改服務端代碼為:

<?php
//這里增加了兩行代碼
header('Access-Control-Allow-Headers:Content-Type');
header('Access-Control-Allow-Methods:PUT');
$requestHeader = getallheaders();
$origin = isset($requestHeader['Origin'])?$requestHeader['Origin']:'';
switch ($origin) {
    case 'http://127.0.0.1':
        header('Access-Control-Allow-Origin:http://127.0.0.1');
        break;
    case 'http://localhost':
        header('Access-Control-Allow-Origin:http://localhost');
        break;
    default:
        break;
}
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

這里雖然成功了,但是我們發(fā)現(xiàn)每次請求的時候會出現(xiàn)兩條請求記錄(這個可不是我請求了兩次,看下面截圖)

這里我們需要進行一下區(qū)分(簡單請求模式與非簡單請求模式)

  • 請求方法只能為GET、HEAD、POST
  • 請求頭中無自定義頭
  • Content-Type必須為text/plain、multipart/form-data、application/x-www-form-urlencoded

符合以上條件的為簡單請求,否則為非簡單請求,注意,非簡單請求中,瀏覽器會默認發(fā)送兩條請求,第一條為預檢請求(OPTION),第二條為AJAX的請求,處于服務器的性能考量,我們需要將預檢命令進行緩存,而不是每次都執(zhí)行預檢請求,我們可以修改代碼如下:

<?php
header('Access-Control-Allow-Headers:Content-Type');
header('Access-Control-Allow-Methods:PUT');
//看這里
header('Access-Control-Max-Age:3600');
$requestHeader = getallheaders();
$origin = isset($requestHeader['Origin'])?$requestHeader['Origin']:'';
switch ($origin) {
    case 'http://127.0.0.1':
        header('Access-Control-Allow-Origin:http://127.0.0.1');
        break;
    case 'http://localhost':
        header('Access-Control-Allow-Origin:http://localhost');
        break;
    default:
        break;
}
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

這次我請求了兩次,發(fā)現(xiàn)第二次請求沒有發(fā)送預檢請求,新增加的代碼代表允許緩存的時間(3600S)。

另外還有一些常用的方法,我都放到這里了,有需要的小伙伴可以參考

<?php
//支持Cookie
header('Access-Control-Allow-Credentials:true');
//支持自定義頭
header('Access-Control-Allow-Headers:token,Content-Type,...');??

由于篇幅有限,Cookie的例子小伙伴們自己做就可以了,使用Cookie的時候需要注意Access-Control-Allow-Origin不可設置為*。

服務軟件實現(xiàn)跨域

上面的例子實現(xiàn)了跨域訪問,但是如果我不想在代碼中修改,還有其他的方法嗎,當然有了,我們可以直接修改服務軟件,下面將從最常用的Apache與Nignx兩個方面說明

基于Apache的服務

<VirtualHost *:80>
  ServerName localhost
  ServerAlias localhost
  DocumentRoot "${INSTALL_DIR}/www"
  
  Header always set Access-Control-Allow-Header "PUT"
  Header always set Access-Control-Allow-Credentials "true"
  Header always set Access-Control-Max-Age "3600"
  #這里設置的為全匹配
  Header always set Access-Control-Allow-Origin "expr=%{req:origin}"
  #這里設置的為全匹配
  Header always set Access-Control-Allow-Headers "expr=%{req:Access-Control-Allow-Headers}"
  
  <Directory "${INSTALL_DIR}/www/">
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    AllowOverride All
    Require local
  </Directory>
</VirtualHost> 

這里說明一下,由于Apache都是模塊管理,所以這里要想使用Header的話,需要加載mod_headers.so這個模塊,去看一下自己的主配置文件,這個模塊是否開啟,如果沒有開啟,apache會啟動失敗的。

LoadModule headers_module modules/mod_headers.so

由于本人學藝不精,Apache的配置中的判斷沒有完全鬧懂,所以這里沒有進行區(qū)分的匹配,如果有大神知道,請指導一下,不勝感激。

基于Nignx的服務

在nignx服務的配置中修改為如下代碼(注意位置,這個例子是修改本地的nignx,沒有域名,如果沒有熟悉過nignx的小伙伴可以自行百度)。

server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    server_name  _;
    root         /usr/share/nginx/html;
    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;
    location / {
            #支持其他請求
            add_header Access-Control-Allow-Methods PUT;
            #設置預檢請求的緩存
            add_header Access-Control-Max-Age 3600;
            #允許Cookie
            add_header Access-Control-Allow-Credentials true;
            #這里最好做判斷,怕麻煩的話就寫*,但是不建議
            if ($http_origin = http://localhost){
                    add_header Access-Control-Allow-Origin http://localhost;
            }
            if ($http_origin = http://127.0.0.1){
                    add_header Access-Control-Allow-Origin http://127.0.0.1;
            }
            #為了方便,這樣寫了
            add_header Access-Control-Allow-Headers $http_access_control_request_headers;
            if ($request_method = OPTIONS){
                    return 200;
            }
    }
    error_page 404 /404.html;
        location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}

另外再說一句,如果您使用的是JAVA的話,可以嘗試一下正反向代理。

總結

到此這篇關于前后端分離和跨域問題解決的文章就介紹到這了,更多相關前后端分離和跨域解決內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • php中iconv函數(shù)使用方法

    php中iconv函數(shù)使用方法

    最近在做一個程序,需要用到iconv函數(shù)把抓取來過的utf-8編碼的頁面轉成gb2312, 發(fā)現(xiàn)只有用iconv函數(shù)把抓取過來的數(shù)據(jù)一轉碼數(shù)據(jù)就會無緣無故的少一些。
    2008-05-05
  • PHP實現(xiàn)會員賬號單唯一登錄的方法分析

    PHP實現(xiàn)會員賬號單唯一登錄的方法分析

    這篇文章主要介紹了PHP實現(xiàn)會員賬號單唯一登錄的方法,結合實例形式分析了php基于session與文件讀寫的單一用戶登陸限制實現(xiàn)技巧,需要的朋友可以參考下
    2019-03-03
  • PHP使用逆波蘭式計算工資的方法

    PHP使用逆波蘭式計算工資的方法

    這篇文章主要介紹了PHP使用逆波蘭式計算工資的方法,實例分析了php逆波蘭式算法的原理與相關使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • PHP5.4中json_encode中文轉碼的變化小結

    PHP5.4中json_encode中文轉碼的變化小結

    在php5.4以前做json_encode的時候中文會被unicode編碼,中文都會被編碼,變成不可讀的,類似“\u***”的格式,接下來介紹幾種5.4之前不進行unicode轉碼的處理方法
    2013-01-01
  • php常用字符串處理函數(shù)實例分析

    php常用字符串處理函數(shù)實例分析

    這篇文章主要介紹了php常用字符串處理函數(shù),以實例形式分析了chop()、get_html_translation_table()、htmlentities()及htmlspecialchars()等函數(shù)的具體用法,對于PHP的學習有著一定的學習與借鑒價值,需要的朋友可以參考下
    2014-11-11
  • PHP實現(xiàn)SQL語句格式化功能的方法

    PHP實現(xiàn)SQL語句格式化功能的方法

    這篇文章主要介紹了PHP實現(xiàn)SQL語句格式化功能的方法,基于github上開源代碼實現(xiàn)的SQL語句格式化功能,非常簡單實用,需要的朋友可以參考下
    2017-07-07
  • php圖片驗證碼代碼

    php圖片驗證碼代碼

    php驗證碼效果代碼
    2008-03-03
  • PHP表單遞交控件名稱含有點號(.)會被轉化為下劃線(_)的處理方法

    PHP表單遞交控件名稱含有點號(.)會被轉化為下劃線(_)的處理方法

    做項目的過程中發(fā)現(xiàn),表單遞交就是不成功,后來發(fā)現(xiàn)原來我給控件的名字不規(guī)范導致,控件遞交到后端之后,發(fā)現(xiàn)所有我控件名字中含有.號的名字,遞交過之后都會被轉化成下劃線_
    2013-01-01
  • php utf-8轉unicode的函數(shù)

    php utf-8轉unicode的函數(shù)

    php下我們想把uft-8,轉成unicode可以用下面的函數(shù)來實現(xiàn)
    2008-06-06
  • 訪問編碼后的中文URL返回404錯誤的解決方法

    訪問編碼后的中文URL返回404錯誤的解決方法

    這篇文章主要介紹了訪問編碼后的中文URL返回404錯誤的解決方法,本文使用的是替換方法,當然也可以使用加密方法來解決,最后附妹子圖一張,需要的朋友可以參考下
    2014-08-08

最新評論