我有一个用 Laravel 和 Sanctum 构建的 API。
前端是用 NextJS 构建的。CORS 和通信运行良好 - 显然,即使使用 POST 请求,我也看不到错误。
登录很顺利,Laravel 为.mydomain.com
路径“/”设置了一个 cookie,并且它只是 HTTP。好的。控制台中没有错误。我可以使用 Laravel Sanctum 的 JWT 在 chrome 开发工具中看到 cookie。
好的,所以在提交登录表单并收到带有jwt
cookie/token的成功响应后,用户将被重定向到主页。在 NextJS 主页中,我有一个功能可以检查会话在 Laravel API 中是否仍然有效。这个函数在getServerSideProps
钩子中运行,也就是 NodeJS。为此,从 NextJS 服务器(NodeJS)向 Laravel API 发出 POST 请求,试图获取有关用户的信息。在这个请求中,cookie 被“转发”到 Laravel。但奇怪的是:请求永远不会到达 Laravel。它正在“命中” NextJS API 路由。而且,当然,该路线在 Next 中不存在。它应该请求 Laravel API。
所以,一步一步:
- 用户
mydomain.com/login
从 NextJS 键入并获取登录页面。 - 用户填写并提交表单。React(客户端)使用 Axios 在
api.mydomain.com/api/login
. - Laravel API 验证表单并
jwt
在响应中设置一个 cookie:
3.1) HTTP Only
3.2) Path: `/`
3.3) Domain: `.mydomain.com` (accordingly to `RFC 6265`
3.4) Value: the JWT token from Laravel Sanctum
在 React 使用 cookie 获得登录响应后
jwt
,React 代码将用户重定向到mydomain.com/
(根 URL)。这是问题的开始。NextJS 将在服务器端运行/构建主页。在 NextJS 的 SSR 期间,Homepage 使用
getServerSideProps
NextJS 中的 hook,并尝试调用api.mydomain.com/api/me
以验证 session/cookie/jwt。但是,由于未知原因,它实际上调用了mydomain.com/api/me
. 请注意,我的 API 在子域中运行api.mydomain.com
,NextJS 在mydomain.com
.
看起来 Axios 正在“忽略”baseURL
配置。但我什至用绝对路径、硬编码的子域替换了相对 URL。仍然看到同样的错误。首先,它导致了 404 页面——因为 NextJS 没有/pages/api/me.ts
文件。我花了很长时间才想到:“嘿,也许这个请求会发送给 NextJS 本身,而不是 Laravel API”。因此,我在 NextJS 中放入了一个输出以下句子的文件:
EERRRROOORRRRRR!!!!永远不应该调用这个,因为 LARAVEL 应该响应这个调用,而不是 NEXTJS API !!!!!!
我可以在日志中看到这个响应。这是我的 HTTP 方法:
export async function me(headers: Headers = {}): Promise<User> {
try {
const config = {
baseURL: 'api.mydomain.com/api',
withCredentials: true,
headers: {
...headers,
},
};
console.log('config', config);
// I was using a global configured instance, but now I'm creating a new one here:
const tempAxios = axios.create(config);
console.log('call HTTP me(). Config:', config);
// the "space" between // and api is only because Stackoverflow blocks URL in the post
const { data } = await tempAxios.get('https:// api.mydomain.com/api/user');
return Promise.resolve(data);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error('call HTTP me() ERROR', error.config);
return Promise.reject(error);
}
}
然后,我可以在 NextJS / Node 日志中看到:
[app-frontend] [2022-03-03 23:39:12] call HTTP me(). Config: {
[app-frontend] [2022-03-03 23:39:12] baseURL: 'api.mydomain.com/api',
[app-frontend] [2022-03-03 23:39:12] withCredentials: true,
[app-frontend] [2022-03-03 23:39:12] headers: {
[app-frontend] [2022-03-03 23:39:12] host: 'mydomain.com',
[app-frontend] [2022-03-03 23:39:12] 'accept-encoding': 'gzip',
[app-frontend] [2022-03-03 23:39:12] 'x-forwarded-for': '2001:818:e889:6600:f4f5:79c0:beb7:etc etc etc',
[app-frontend] [2022-03-03 23:39:12] 'x-forwarded-proto': 'https',
[app-frontend] [2022-03-03 23:39:12] 'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"',
[app-frontend] [2022-03-03 23:39:12] 'sec-ch-ua-mobile': '?0',
[app-frontend] [2022-03-03 23:39:12] 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
[app-frontend] [2022-03-03 23:39:12] 'sec-ch-ua-platform': '"macOS"',
[app-frontend] [2022-03-03 23:39:12] accept: '*/*',
[app-frontend] [2022-03-03 23:39:12] 'sec-fetch-site': 'same-origin',
[app-frontend] [2022-03-03 23:39:12] 'sec-fetch-mode': 'cors',
[app-frontend] [2022-03-03 23:39:12] 'sec-fetch-dest': 'empty',
[app-frontend] [2022-03-03 23:39:12] referer: 'mydomain.com/login',
[app-frontend] [2022-03-03 23:39:12] 'accept-language': 'pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7',
[app-frontend] [2022-03-03 23:39:12] cookie: 'jwt=75%7C4VyknPf8Jb2papbla-bla-bla',
[app-frontend] [2022-03-03 23:39:12] 'cdn-loop': 'cloudflare',
[app-frontend] [2022-03-03 23:39:12] 'do-connecting-ip': '2001:818:etc',
[app-frontend] [2022-03-03 23:39:12] 'Content-Type': 'application/json',
[app-frontend] [2022-03-03 23:39:12] Accept: 'application/json'
[app-frontend] [2022-03-03 23:39:12] }
[app-frontend] [2022-03-03 23:39:12] }
[app-frontend] [2022-03-03 23:39:12] EERRRROOORRRRRR!!!! THIS SHOULD NEVER BE CALLED, SINCE LARAVEL SHOULD ANSWER THIS CALL, NOT NEXTJS API!!!!!
上面日志的最后一行只存在,因为 Axios 在 NextJS SSR 期间调用了错误的域。所以,无论我做什么,请求总是命中mydomain.com/api/me
,而不是api.mydomain.com
. 我在 DigitalOcean Apps 平台上完成所有这些工作。使用控制台,我可以手动运行debug.js
类似的文件node debug.js
,它可以正确获取 URL/有效负载。但是,在 NextJS 中,baseURL
被忽略了,请求总是转到 NextJS。
我不知道我还应该在这里做什么。因为login
路线很好。我不确定是否是因为config.headers.host
这阻止了请求转到子域。
非常感谢任何帮助。