文章
nextjs 解析api数据
方式1:
"use client";
export default function Home() {
async function getApiData() {
const response = await fetch("http://127.0.0.1:8000/");
const data = await response.json();
console.log(data);
}
async function handleClick() {
await getApiData();
}
return (
<div>
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<button onClick={handleClick}>
Lookup Data
</button>
</main>
</div>
方式2:
"use client";
import {useState} from "react";
export default function Home() {
const [datsStr, setDatsStr] = useState("");
async function getApiData() {
const response = await fetch("http://127.0.0.1:8000/");
const data = await response.json();
setDatsStr(JSON.stringify(data));
}
async function handleClick() {
await getApiData();
}
return (
<div>
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<button onClick={handleClick}>
Lookup Data
</button>
<div>
{datsStr}
</div>
</main>
</div>
方式3:
npm install swr
import useSWR from "swr";
const fetcher = (...args) => fetch(...args).then(res => res.json());
xport default function Home() {
const {data, error, isLoading} = useSWR("http://127.0.0.1:8000/", fetcher);
if (isLoading) {
return (
<div>
loading...
</div>
)
}
if (error) {
return (
<div>
failed to load
</div>
)
}
return (
<div>
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
{JSON.stringify(data)}
</main>
</div>
提交nextjs提交表单数据
formData格式
"use client";
const LOGIN_URL = "http://localhost:8000/auth/token";
export default function Page() {
async function handleSubmit(event) {
// 禁止页面地址跳转 会拼接form表单中的key和value到提交地址中/login?username=xxx&password=xxx
event.preventDefault();
// event.target <form>标签里的html内容
console.log(event, event.target);
// 构建表单数据
const formData = new FormData(event.target);
// 构建请求信息:请求方式、请求头、请求体
const requestOptions = {
method: "POST",
body: formData,
}
const response = await fetch(LOGIN_URL, requestOptions);
if (response.ok) {
const rData = await response.json();
console.log(rData);
}
}
return (
<div className="h-[95vh]">
<div className="max-w-md mx-auto py-5">
<h1>Login Here</h1>
<form onSubmit={handleSubmit}>
<input type="text" required name="username" placeholder="Your Username" />
<input type="password" required name="password" placeholder="Your Password" />
<button type="submit">Login</button>
</form>
</div>
</div>
)
}
formdata转json格式
"use client";
const LOGIN_URL = "http://localhost:8000/auth/token";
export default function Page() {
async function handleSubmit(event) {
// 禁止页面地址跳转 会拼接form表单中的key和value到提交地址中/login?username=xxx&password=xxx
event.preventDefault();
// event.target <form>标签里的html内容
console.log(event, event.target);
// 构建表单数据
const formData = new FormData(event.target);
// 从表单中获取数据对象
const objectFromForm = Object.fromEntries(formData);
// 将对象转换为json格式 {"username":"xxx","password":"xxx"}
const jsonData = JSON.stringify(objectFromForm);
// console.log(jsonData);
// 构建请求信息:请求方式、请求头、请求体
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: jsonData,
}
const response = await fetch(LOGIN_URL, requestOptions);
if (response.ok) {
const rData = await response.json();
console.log(rData);
}
}
return (
<div className="h-[95vh]">
<div className="max-w-md mx-auto py-5">
<h1>Login Here</h1>
<form onSubmit={handleSubmit}>
<input type="text" required name="username" placeholder="Your Username" />
<input type="password" required name="password" placeholder="Your Password" />
<button type="submit">Login</button>
</form>
</div>
</div>
)
}
cookie设置
/app/login/page.jsx
"use client";
// const LOGIN_URL = "http://localhost:8000/auth/token_v2";
// 访问next js的地址/api/login 使用route.jsx可以定义不同method的请求方式来处理不同的请求 同时也可以使用USE SERVER
const LOGIN_URL = "/api/login";
export default function Page() {
async function handleSubmit(event) {
// 整体思路:
// 1、获取表单数据 转换成json格式 将数据发送给 nextjs /api/login
// 2、/api/login 获取数据将数据发送给fastapi后端获取到access_token 并将 token设置到session中
// 禁止页面地址跳转 会拼接form表单中的key和value到提交地址中/login?username=xxx&password=xxx
event.preventDefault();
// event.target <form>标签里的html内容
console.log(event, event.target);
// 构建表单数据
const formData = new FormData(event.target);
// 从表单中获取数据对象
const objectFromForm = Object.fromEntries(formData);
// 将对象转换为json格式 {"username":"xxx","password":"xxx"}
const jsonData = JSON.stringify(objectFromForm);
// console.log(jsonData);
// 构建请求信息:请求方式、请求头、请求体
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: jsonData,
}
// 从next js 定义的 /api/login 地址请求数据
const response = await fetch(LOGIN_URL, requestOptions);
const data = await response.json();
console.log(data);
if (response.ok) {
console.log("login success");
}
}
return (
<div className="h-[95vh]">
<div className="max-w-md mx-auto py-5">
<h1>Login Here</h1>
<form onSubmit={handleSubmit}>
<input type="text" required name="username" placeholder="Your Username" />
<input type="password" required name="password" placeholder="Your Password" />
<button type="submit">Login</button>
</form>
</div>
</div>
)
}
整体思路:
1、获取表单数据 转换成json格式 将数据发送给 nextjs /api/login
2、/api/login 获取数据将数据发送给fastapi后端获取到access_token 并将 token设置到session中
/app/api/login/route.jsx
"use server";
import {cookies} from "next/headers";
import {NextResponse} from "next/server";
const FASTAPI_LOGIN_URL = "http://localhost:8000/auth/token_v2";
export async function POST(request) {
// 获取cookie next js 13 之后需要先await
const cookieStore = await cookies();
const myAuthToken = cookieStore.get("auth-token");
console.log(myAuthToken);
// 获取/login发来的请求数据
const requestData = await request.json();
// 会在终端打印,不在浏览器客户端打印
// console.log(requestData);
// 转换json格式
const jsonData = JSON.stringify(requestData);
// console.log(jsonData);
// 构建请求信息:请求方式、请求头、请求体
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: jsonData,
}
// 向fastapi请求数据
const response = await fetch(FASTAPI_LOGIN_URL, requestOptions);
const responseData = await response.json();
// console.log(responseData);
if (response.ok) {
console.log("login success");
const authToken = responseData.access_token;
cookieStore.set({
name: "auth-token",
value: authToken,
httpOnly: true,
sameSite: "strict",
secure: process.env.NODE_ENV !== "development",
maxAge: 3600
});
}
return NextResponse.json({"hello": "world", "cookie": myAuthToken}, {status: 200});
}
封装auth方法
/app/lib/auth.jsx
import {cookies} from "next/headers";
const TOKEN_AGE = 3600;
const TOKEN_NAME = "auth-token";
const TOKEN_REFRESH_TOKEN = "auth-refresh-token";
// 获取 CookieStore(单例模式)
async function getCookieStore() {
return await cookies();
}
export async function getToken() {
// api request
const cookieStore = await getCookieStore();
const myAuthToken = cookieStore.get(TOKEN_NAME);
return myAuthToken?.value;
}
export async function getRefreshToken() {
// api request
const cookieStore = await getCookieStore();
const myAuthToken = cookieStore.get(TOKEN_REFRESH_TOKEN);
return myAuthToken?.value;
}
export async function setToken(authToken) {
// login
const cookieStore = await getCookieStore();
cookieStore.set({
name: TOKEN_NAME,
value: authToken,
httpOnly: true,
sameSite: "strict",
secure: process.env.NODE_ENV !== "development",
maxAge: TOKEN_AGE
});
}
export async function setRefreshToken(authRefreshToken) {
// login
const cookieStore = await getCookieStore();
cookieStore.set({
name: TOKEN_REFRESH_TOKEN,
value: authRefreshToken,
httpOnly: true,
sameSite: "strict",
secure: process.env.NODE_ENV !== "development",
maxAge: TOKEN_AGE
});
}
export async function deleteToken() {
// logout
const cookieStore = await getCookieStore();
cookieStore.delete(TOKEN_REFRESH_TOKEN);
return cookieStore.delete(TOKEN_NAME);
}
修改/app/api/login/route.jsx
"use server";
import {NextResponse} from "next/server";
import {getRefreshToken, getToken, setRefreshToken, setToken} from "@/app/lib/auth";
const FASTAPI_LOGIN_URL = "http://localhost:8000/auth/token_v2";
export async function POST(request) {
const myAuthToken = await getToken();
const myRefreshAuthToken = await getRefreshToken();
console.log(myAuthToken, myRefreshAuthToken);
// 获取/login发来的请求数据
const requestData = await request.json();
// 会在终端打印,不在浏览器客户端打印
// console.log(requestData);
// 转换json格式
const jsonData = JSON.stringify(requestData);
// console.log(jsonData);
// 构建请求信息:请求方式、请求头、请求体
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: jsonData,
}
// 向fastapi请求数据
const response = await fetch(FASTAPI_LOGIN_URL, requestOptions);
const responseData = await response.json();
// console.log(responseData);
if (response.ok) {
console.log("login success");
const {access_token, refresh_token} = responseData;
await setToken(access_token);
await setRefreshToken(refresh_token);
}
return NextResponse.json({"hello": "world", "cookie": myAuthToken}, {status: 200});
}
logout功能实现
/app/api/logout/route.jsx
import {deleteToken} from "@/app/lib/auth";
import {NextResponse} from "next/server";
export async function POST(request) {
await deleteToken();
return NextResponse.json({}, {status: 200});
}
/app/logout/page.jsx
"use client";
import {useRouter} from "next/navigation";
const LOGOUT_URL = "/api/logout";
export default function Page() {
const router = useRouter();
async function handleClick(event) {
event.preventDefault();
// 构建请求信息:请求方式、请求头、请求体
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: "",
}
// 从next js 定义的 /api/login 地址请求数据
const response = await fetch(LOGOUT_URL, requestOptions);
if (response.ok) {
console.log("logout success");
router.replace("/login");
}
}
return (
<div className="h-[95vh]">
<div className="max-w-md mx-auto py-5">
<h1>Are you sure you want to logout?</h1>
<button className="bg-red-500 text-white hover:bg-red-300 px-3 py-2" onClick={handleClick}>
Yes, logout
</button>
</div>
</div>
)
}