@quicktvui/web-cli 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/DevServer.js CHANGED
@@ -494,42 +494,86 @@ class DevServer {
494
494
 
495
495
  /**
496
496
  * 处理代理请求
497
+ *
498
+ * URL 格式: /proxy/{http|https}/{host}[:port]/{path}[?query]
499
+ * 示例:
500
+ * /proxy/https/api.example.com/v1/data → https://api.example.com/v1/data
501
+ * /proxy/https/api.example.com:8443/v1/data → https://api.example.com:8443/v1/data
497
502
  */
498
503
  _handleProxy(req, res, pathname) {
499
- // /proxy/https/example.com/path https://example.com/path
504
+ // 从完整 URL 中提取查询参数(pathname 只有路径部分)
505
+ const fullUrl = url.parse(req.url, true)
506
+ const queryString = fullUrl.search || ''
507
+
500
508
  const match = pathname.match(/^\/proxy\/(https?)\/([^/]+)(\/.*)?$/)
501
509
  if (!match) {
502
510
  res.writeHead(400, { 'Content-Type': 'text/plain' })
503
- res.end('Invalid proxy URL format. Use: /proxy/{http|https}/{host}/{path}')
511
+ res.end('Invalid proxy URL format. Use: /proxy/{http|https}/{host}[:port]/{path}')
504
512
  return
505
513
  }
506
514
 
507
515
  const protocol = match[1]
508
- const host = match[2]
509
- const proxyPath = match[3] || '/'
516
+ const hostPort = match[2]
517
+ const proxyPath = (match[3] || '/') + queryString
518
+
519
+ // 分离 host 和 port
520
+ let hostname = hostPort
521
+ let port = protocol === 'https' ? 443 : 80
522
+ if (hostPort.includes(':')) {
523
+ const parts = hostPort.split(':')
524
+ hostname = parts[0]
525
+ port = parseInt(parts[1], 10) || port
526
+ }
527
+
528
+ // 过滤掉 hop-by-hop 头,避免转发问题
529
+ const headers = { ...req.headers }
530
+ delete headers['host']
531
+ delete headers['connection']
532
+ delete headers['keep-alive']
533
+ delete headers['transfer-encoding']
534
+ delete headers['te']
535
+ delete headers['trailer']
536
+ delete headers['upgrade']
537
+ delete headers['proxy-connection']
538
+ headers['host'] = hostPort
539
+ // 标记请求来自代理(方便调试)
540
+ headers['x-forwarded-for'] = req.socket.remoteAddress
541
+ headers['x-forwarded-proto'] = protocol
510
542
 
511
543
  const options = {
512
- hostname: host,
513
- port: protocol === 'https' ? 443 : 80,
544
+ hostname,
545
+ port,
514
546
  path: proxyPath,
515
547
  method: req.method,
516
- headers: {
517
- ...req.headers,
518
- host: host,
519
- },
548
+ headers,
549
+ rejectUnauthorized: false, // 允许自签名证书
520
550
  }
521
551
 
522
552
  const httpModule = protocol === 'https' ? require('https') : require('http')
523
553
  const proxyReq = httpModule.request(options, (proxyRes) => {
524
- res.writeHead(proxyRes.statusCode, proxyRes.headers)
554
+ // 代理响应添加 CORS 头
555
+ const responseHeaders = { ...proxyRes.headers }
556
+ responseHeaders['access-control-allow-origin'] = this.corsOrigin
557
+ responseHeaders['access-control-allow-methods'] = 'GET, POST, PUT, DELETE, OPTIONS, PATCH'
558
+ responseHeaders['access-control-allow-headers'] = '*'
559
+ responseHeaders['access-control-allow-credentials'] = 'true'
560
+ // 移除可能导致问题的安全头
561
+ delete responseHeaders['x-frame-options']
562
+ delete responseHeaders['content-security-policy']
563
+
564
+ res.writeHead(proxyRes.statusCode, responseHeaders)
525
565
  proxyRes.pipe(res)
526
566
  })
527
567
 
528
568
  proxyReq.on('error', (err) => {
529
- res.writeHead(502, { 'Content-Type': 'text/plain' })
530
- res.end(`Proxy error: ${err.message}`)
569
+ console.error(`[Proxy] Error: ${err.message} -> ${protocol}://${hostname}:${port}${proxyPath}`)
570
+ if (!res.headersSent) {
571
+ res.writeHead(502, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': this.corsOrigin })
572
+ }
573
+ res.end(JSON.stringify({ error: 'Proxy error', message: err.message, target: `${protocol}://${hostname}:${port}${proxyPath}` }))
531
574
  })
532
575
 
576
+ // 转发请求体(POST/PUT 等)
533
577
  req.pipe(proxyReq)
534
578
  }
535
579
 
@@ -538,8 +582,9 @@ class DevServer {
538
582
  */
539
583
  _setCORSHeaders(res) {
540
584
  res.setHeader('Access-Control-Allow-Origin', this.corsOrigin)
541
- res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS')
542
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
585
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH')
586
+ res.setHeader('Access-Control-Allow-Headers', '*')
587
+ res.setHeader('Access-Control-Allow-Credentials', 'true')
543
588
  }
544
589
 
545
590
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quicktvui/web-cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "CLI tool for QuickTVUI web development v2 - delegate build & bundle loading",
5
5
  "author": "QuickTVUI Team",
6
6
  "license": "Apache-2.0",