Compare commits
5 Commits
c4c17180ee
...
master-tes
| Author | SHA1 | Date | |
|---|---|---|---|
| b9f78cacf1 | |||
| 74d2103290 | |||
| a478c902be | |||
| b0d25b30f9 | |||
| ac30d8d1c9 |
24
README.md
24
README.md
@@ -186,6 +186,30 @@ php webman migrate
|
|||||||
|
|
||||||
> 注意:前端通过 Vite 代理将 `/api`、`/admin`、`/install` 转发到后端 8787 端口,请勿直接访问 8787 端口的前端页面,否则可能出现 404。
|
> 注意:前端通过 Vite 代理将 `/api`、`/admin`、`/install` 转发到后端 8787 端口,请勿直接访问 8787 端口的前端页面,否则可能出现 404。
|
||||||
|
|
||||||
|
### 5.6 生产环境 Nginx(反向代理 Webman)
|
||||||
|
|
||||||
|
部署到服务器时,若使用 **Nginx** 作为站点入口,需将请求转发到本机 **Webman** 进程(默认监听端口与 `config/process.php` 中 `listen` 一致,一般为 `8787`,反代目标使用 `127.0.0.1:8787`)。
|
||||||
|
|
||||||
|
在站点 **`server { }`** 块中可增加如下写法:**先由 Nginx 根据 `root` 判断是否存在对应静态文件;不存在则转发到 Webman**(`root` 建议指向项目 `public` 目录)。
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
location ^~ / {
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Connection "";
|
||||||
|
if (!-f $request_filename) {
|
||||||
|
proxy_pass http://127.0.0.1:8787;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
修改配置后执行 `nginx -t` 校验,再重载 Nginx;并确保 Webman 已启动(如 `php start.php start -d`)。
|
||||||
|
|
||||||
|
若前端与接口为**不同域名**(跨域),除反代外还需保证 **HTTPS 证书与域名一致**,以及后端 **CORS / 预检(OPTIONS)** 与前端请求头(如 `think-lang`、`server` 等)配置一致,否则浏览器会报跨域相关错误。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 六、路由说明
|
## 六、路由说明
|
||||||
|
|||||||
@@ -21,46 +21,6 @@ class AllowCrossDomain implements MiddlewareInterface
|
|||||||
'Access-Control-Allow-Headers' => '*',
|
'Access-Control-Allow-Headers' => '*',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 Origin 与配置写入 Access-Control-Allow-Origin。
|
|
||||||
* 注意:* 与 Access-Control-Allow-Credentials:true 不能同时出现,故通配时去掉 Credentials。
|
|
||||||
*/
|
|
||||||
private static function applyCorsOrigin(Request $request, array $header): array
|
|
||||||
{
|
|
||||||
$origin = $request->header('origin');
|
|
||||||
if (is_array($origin)) {
|
|
||||||
$origin = $origin[0] ?? '';
|
|
||||||
}
|
|
||||||
$origin = is_string($origin) ? trim($origin) : '';
|
|
||||||
|
|
||||||
$corsDomain = array_map('trim', explode(',', config('buildadmin.cors_request_domain', '')));
|
|
||||||
$corsDomain[] = $request->host(true);
|
|
||||||
$wildcard = in_array('*', $corsDomain);
|
|
||||||
|
|
||||||
if ($origin !== '') {
|
|
||||||
$info = parse_url($origin);
|
|
||||||
$host = '';
|
|
||||||
if (is_array($info)) {
|
|
||||||
$host = $info['host'] ?? '';
|
|
||||||
}
|
|
||||||
$allowed = $wildcard
|
|
||||||
|| in_array($origin, $corsDomain)
|
|
||||||
|| in_array($host, $corsDomain)
|
|
||||||
|| ($host === 'localhost' || $host === '127.0.0.1');
|
|
||||||
if ($allowed) {
|
|
||||||
$header['Access-Control-Allow-Origin'] = $origin;
|
|
||||||
}
|
|
||||||
return $header;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($wildcard) {
|
|
||||||
$header['Access-Control-Allow-Origin'] = '*';
|
|
||||||
unset($header['Access-Control-Allow-Credentials']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $header;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回 CORS 预检(OPTIONS)响应,供路由直接调用(Webman 未匹配路由时不走中间件)
|
* 返回 CORS 预检(OPTIONS)响应,供路由直接调用(Webman 未匹配路由时不走中间件)
|
||||||
*/
|
*/
|
||||||
@@ -70,9 +30,26 @@ class AllowCrossDomain implements MiddlewareInterface
|
|||||||
'Access-Control-Allow-Credentials' => 'true',
|
'Access-Control-Allow-Credentials' => 'true',
|
||||||
'Access-Control-Max-Age' => '1800',
|
'Access-Control-Max-Age' => '1800',
|
||||||
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
||||||
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, batoken, ba-user-token, think-lang',
|
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, batoken, ba-user-token, think-lang, server',
|
||||||
];
|
];
|
||||||
$header = self::applyCorsOrigin($request, $header);
|
$origin = $request->header('origin');
|
||||||
|
if (is_array($origin)) {
|
||||||
|
$origin = $origin[0] ?? '';
|
||||||
|
}
|
||||||
|
$origin = is_string($origin) ? trim($origin) : '';
|
||||||
|
if ($origin !== '') {
|
||||||
|
$info = parse_url($origin);
|
||||||
|
$host = $info['host'] ?? '';
|
||||||
|
$corsDomain = array_map('trim', explode(',', config('buildadmin.cors_request_domain', '')));
|
||||||
|
$corsDomain[] = $request->host(true);
|
||||||
|
$allowed = in_array('*', $corsDomain)
|
||||||
|
|| in_array($origin, $corsDomain)
|
||||||
|
|| in_array($host, $corsDomain)
|
||||||
|
|| ($host === 'localhost' || $host === '127.0.0.1');
|
||||||
|
if ($allowed) {
|
||||||
|
$header['Access-Control-Allow-Origin'] = $origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
return response('', 204, $header);
|
return response('', 204, $header);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +60,29 @@ class AllowCrossDomain implements MiddlewareInterface
|
|||||||
return $handler($request);
|
return $handler($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
$header = self::applyCorsOrigin($request, $this->header);
|
$header = $this->header;
|
||||||
|
|
||||||
|
$origin = $request->header('origin');
|
||||||
|
if (is_array($origin)) {
|
||||||
|
$origin = $origin[0] ?? '';
|
||||||
|
}
|
||||||
|
$origin = is_string($origin) ? trim($origin) : '';
|
||||||
|
|
||||||
|
if ($origin !== '') {
|
||||||
|
$info = parse_url($origin);
|
||||||
|
$host = $info['host'] ?? '';
|
||||||
|
$corsDomain = array_map('trim', explode(',', config('buildadmin.cors_request_domain', '')));
|
||||||
|
$corsDomain[] = $request->host(true);
|
||||||
|
|
||||||
|
$allowed = in_array('*', $corsDomain)
|
||||||
|
|| in_array($origin, $corsDomain)
|
||||||
|
|| in_array($host, $corsDomain)
|
||||||
|
|| ($host === 'localhost' || $host === '127.0.0.1');
|
||||||
|
|
||||||
|
if ($allowed) {
|
||||||
|
$header['Access-Control-Allow-Origin'] = $origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->method() === 'OPTIONS') {
|
if ($request->method() === 'OPTIONS') {
|
||||||
return response('', 204, $header);
|
return response('', 204, $header);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class Http extends App
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 在父类处理前拦截 OPTIONS 预检,直接返回 CORS 头(避免预检未命中路由时无 CORS)
|
* 在父类处理前拦截 OPTIONS 预检,直接返回 CORS 头(避免预检未命中路由时无 CORS)
|
||||||
* 与 AllowCrossDomain::optionsResponse 一致,避免 * + Allow-Credentials 组合被浏览器拒绝
|
* 必须与 AllowCrossDomain::optionsResponse 一致,否则会覆盖中间件里对 Allow-Headers(如 server)的配置
|
||||||
*/
|
*/
|
||||||
public function onMessage($connection, $request): void
|
public function onMessage($connection, $request): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
# BuildAdmin Webman - Nginx 反向代理示例
|
|
||||||
# 将 server_name 和 root 改为实际值后,放入 nginx 的 conf.d 或 sites-available
|
|
||||||
|
|
||||||
upstream webman {
|
|
||||||
server 127.0.0.1:8787;
|
|
||||||
keepalive 10240;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
server_name 你的域名;
|
|
||||||
listen 80;
|
|
||||||
access_log off;
|
|
||||||
root /path/to/dafuweng-webman/public;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ @proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
location @proxy {
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Connection "";
|
|
||||||
proxy_pass http://webman;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ \.php$ {
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/\.well-known/ {
|
|
||||||
allow all;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ /\. {
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user