我有一個簡單的登錄后端,它有兩個路由 login 和 get_user。用戶登錄后,會設定一個 cookie 以啟用其他路由,例如 get_user。我用 Postman 測驗了這個后端,在正確登錄后,cookie 被設定并且 get_user 用用戶的資料回應。
但是,當我嘗試在 React 和 JS 中使用 fetch 或 axios 時,我遇到了問題。獲取登錄資訊后,我可以看到 cookie 已發送,但是,獲取 get_user 的行為就像根本沒有設定 cookie。
我提供了一個最小的示例來說明服務器端會話在某種程度上不適用于 fetch:
前端:
<!DOCTYPE html>
<html>
<body>
<h1> Set value: </h1> <h2 id="set_value"></h2>
<h1> Get value: </h1> <h2 id="get_value"></h2>
</body>
<script>
// ..\..\Flask_general_framework\backend\venv\Scripts\Activate.ps1
async function Set_user_fetch()
{
// Get user
let user = await fetch('http://127.0.0.1:5000/set/gggg', {
'method': 'GET',
//credentials: 'include',
mode: 'cors',
credentials: "same-origin",
headers: {'Content-type': 'application/json', 'Accept': 'application/json',
'Access-Control-Allow-Origin': '*', // Required for CORS support to work
'Access-Control-Allow-Credentials': true, // Required for cookies, authorization headers with HTTPS},
'Access-Control-Allow-Headers': 'Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name',
}
})
user = await user.json();
console.log("await user:", user);
document.getElementById("set_value").innerHTML = user.value;
}
async function Get_user_fetch()
{
let user = await fetch('http://127.0.0.1:5000/get', {
'method': 'GET',
//credentials: 'include',
credentials: "same-origin",
mode: 'cors',
headers: {'Content-type': 'application/json', 'Accept': 'application/json',
'Access-Control-Allow-Origin': '*', // Required for CORS support to work
'Access-Control-Allow-Credentials': true, // Required for cookies, authorization headers with HTTPS},
'Access-Control-Allow-Headers': 'Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name',
}
})
user = await user.json();
console.log("await user:", user);
document.getElementById("get_value").innerHTML = user.value;
}
Set_user_fetch().then( () => {
Get_user_fetch();
});
</script>
</html>
后端:
from re import I
from flask import Flask, session
from flask_session import Session
from flask_cors import CORS
import redis
import datetime as dt
app = Flask(__name__)
CORS(app, supports_credentials=True)
app.config['SECRET_KEY'] = 'super secret key'
#app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_PERMANENT'] = True
#app.config['SESSION_REDIS'] = redis.from_url('redis://localhost:9876')
app.config['PERMANENT_SESSION_LIFETIME'] = dt.timedelta(days=7).total_seconds()
server_session = Session()
server_session.init_app(app)
@app.route('/set/<value>', methods=['GET', 'POST'])
def set_value(value):
session['value'] = value
return {"value": value}
@app.route('/get', methods=['GET', 'POST'])
def get_value():
return {"value": session.get('value', 'None')}
app.run(host='127.0.0.1', port=5000, debug=True)
uj5u.com熱心網友回復:
服務器端
為了在現代瀏覽器中支持跨站點 cookie,您需要配置您的服務器以使用該Set-Cookie屬性SameSite=None(請參閱此處的 Flask 特定示例)。不幸的是,這也需要Secure屬性和HTTPS啟用的服務器。
對于本地開發,您可以通過在相同的主機名上為您的客戶端和服務器提供服務來解決此問題,例如localhost使用SameSite=Lax(或省略SameSite默認為“Lax”)。
“相同的主機名”是指如果您的前端代碼向 發出請求localhost:5000,您應該在瀏覽器中打開它http://localhost:<frontend-port>。同樣,如果您向 提出請求127.0.0.1:5000,您應該在 中打開它http://127.0.0.1:<frontend-port>。
如果只是埠不同,那么寬松的同站點限制就不會發揮作用。
客戶端
你這里有幾個問題...
- 您在請求中發送不屬于那里的標頭。
Access-Control-Allow-*是必須來自服務器的回應標頭。 - 您設定
credentials為same-origin但正在向其他主機發送請求。要使用 cookie,您需要設定credentials為"include". 請參閱Request.credentials。 - 對于不成功的請求,您沒有錯誤處理。
您還設定了許多冗余屬性和標頭,并且可以顯著減少您的代碼。
async function Set_user_fetch() {
const res = await fetch("http://127.0.0.1:5000/set/gggg", {
credentials: "include",
});
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
const user = await res.json();
console.log("await user:", user);
document.getElementById("set_value").innerHTML = user.value;
}
async function Get_user_fetch() {
const res = await fetch("http://127.0.0.1:5000/get", {
credentials: "include",
});
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
const user = await res.json();
console.log("await user:", user);
document.getElementById("get_value").innerHTML = user.value;
}
如果您使用的是 Axios,您可以將withCredentials配置設定為true
axios.get("http://127.0.0.1:5000/set/gggg", {
withCredentials: true
});
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/459286.html
