You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_QLine/CORS_ISSUE_SOLUTION.md

270 lines
7.7 KiB
Markdown

# CORS Issue - Web SignalR Connection & API Calls
## Problem
```
ClientException: Failed to fetch, uri=https://ms.hmg.com/nscapi/PatientCallingHub/negotiate?IPAddress=10.71.50.53
ClientException: Failed to fetch, uri=https://ms.hmg.com/nscapi/api/PatientCall/Common_Config_GetByIP
```
### What is CORS?
CORS (Cross-Origin Resource Sharing) is a browser security feature that blocks web apps from making requests to different domains unless the server explicitly allows it.
- ✅ **Mobile app**: Works fine (no CORS restrictions)
- ❌ **Web app**: Blocked by browser (CORS policy)
## Why This Happens
The web app is trying to connect to:
```
https://ms.hmg.com/nscapi/PatientCallingHub (SignalR Hub)
https://ms.hmg.com/nscapi/api/PatientCall/* (REST APIs)
https://ms.hmg.com/nscapi/api/Gen/* (Generic APIs)
https://ms.hmg.com/nscapi/api/Common/* (Common APIs)
```
But the browser blocks it because:
1. The web app is running on a different origin (e.g., `http://localhost:port` or `http://device-ip:port`)
2. The server (`ms.hmg.com`) doesn't send CORS headers allowing the web app's origin
**⚠️ IMPORTANT:** CORS must be configured for **ALL API endpoints**, not just SignalR!
## Solutions
### **Solution 1: Configure CORS on Server (RECOMMENDED)**
The backend server needs to add CORS headers to allow web requests. The server admin needs to configure:
#### For ASP.NET Core (SignalR Hub + REST APIs):
**In `Startup.cs` or `Program.cs`:**
```csharp
public void ConfigureServices(IServiceCollection services)
{
// Add CORS policy - MUST be before other services
services.AddCors(options =>
{
options.AddPolicy("AllowQLineWeb", builder =>
{
builder
.WithOrigins(
"http://localhost:*", // Development
"http://10.71.50.53:*", // Device IP
"https://qline.hmg.com", // Production
"https://your-web-domain.com" // Your web domain
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials() // Required for SignalR
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
// Add SignalR
services.AddSignalR();
// Add MVC/API Controllers
services.AddControllers();
}
public void Configure(IApplicationBuilder app)
{
// CRITICAL: Enable CORS BEFORE routing and endpoints
app.UseCors("AllowQLineWeb");
// Other middleware...
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
// Apply CORS to SignalR hub
endpoints.MapHub<PatientCallingHub>("/PatientCallingHub")
.RequireCors("AllowQLineWeb");
// Apply CORS to API controllers (applies to ALL API routes)
endpoints.MapControllers()
.RequireCors("AllowQLineWeb");
});
}
```
**Alternative for Controllers (if endpoints not working):**
Add `[EnableCors("AllowQLineWeb")]` to your controllers:
```csharp
[ApiController]
[Route("api/[controller]")]
[EnableCors("AllowQLineWeb")] // Add this to EACH controller
public class PatientCallController : ControllerBase
{
// Your actions here...
}
```
#### For IIS:
Add to `web.config`:
```xml
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
</system.webServer>
```
---
### **Solution 2: Run Web App from Same Domain**
Deploy the web app to the same domain as the API:
- API: `https://ms.hmg.com/nscapi`
- Web App: `https://ms.hmg.com/qline-web` ✅ (Same origin, no CORS issue)
---
### **Solution 3: Use Reverse Proxy (Development)**
For local development, use a reverse proxy to avoid CORS:
#### Using Flutter web with proxy:
1. Create `proxy_server.js`:
```javascript
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use('/nscapi', createProxyMiddleware({
target: 'https://ms.hmg.com',
changeOrigin: true,
ws: true, // Proxy websockets for SignalR
}));
app.listen(3000, () => {
console.log('Proxy running on http://localhost:3000');
});
```
2. Update `ApiConstants` to use proxy:
```dart
static String baseUrl = kIsWeb ? 'http://localhost:3000/nscapi' : 'https://ms.hmg.com/nscapi';
```
---
### **Solution 4: Browser Extension (Development Only)**
For testing, use a CORS browser extension:
- Chrome: "CORS Unblock" or "Allow CORS"
- Firefox: "CORS Everywhere"
⚠️ **Warning**: Only for development! Don't use in production.
---
## Quick Test
To verify CORS is the issue, open browser console and run:
### Test SignalR Hub:
```javascript
fetch('https://ms.hmg.com/nscapi/PatientCallingHub/negotiate?IPAddress=10.71.50.53')
.then(r => console.log('✅ SignalR CORS working!', r))
.catch(e => console.error('❌ SignalR CORS blocked:', e));
```
### Test Configuration API:
```javascript
fetch('https://ms.hmg.com/nscapi/api/PatientCall/Common_Config_GetByIP', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ipAddress: '10.71.50.53', apiKey: 'EE17D21C7943485D9780223CCE55DCE5' })
})
.then(r => console.log('✅ Config API CORS working!', r))
.catch(e => console.error('❌ Config API CORS blocked:', e));
```
### Test Weather API:
```javascript
fetch('https://ms.hmg.com/nscapi/api/PatientCall/WeatherForecast_GetBy5Days', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cityID: '297030' })
})
.then(r => console.log('✅ Weather API CORS working!', r))
.catch(e => console.error('❌ Weather API CORS blocked:', e));
```
If you see "CORS blocked" errors, the server needs CORS configuration.
---
## Current Status
- ✅ IP persistence: FIXED (localStorage working)
- ✅ IP retrieval on reload: FIXED
- ❌ SignalR connection on web: **BLOCKED BY CORS**
- ❌ REST API calls on web: **BLOCKED BY CORS**
- ❌ Configuration API on web: **BLOCKED BY CORS**
- ✅ All functionality on mobile: Working fine
**IMPORTANT:** The web app requires CORS for:
1. SignalR Hub (`/PatientCallingHub`)
2. Configuration API (`/api/PatientCall/Common_Config_GetByIP`)
3. Weather API (`/api/PatientCall/WeatherForecast_GetBy5Days`)
4. Prayer API (`/api/PatientCall/PrayerTime_Today`)
5. RSS Feed API (`/api/PatientCall/RssFeed_Get`)
6. Ticket APIs (`/api/Common/*`, `/api/Gen/*`)
**All APIs must have CORS enabled for web deployment.**
---
## Next Steps
1. **Contact backend/server admin** to add CORS headers for web app
2. **Provide them the allowed origins**:
- Development: `http://localhost:*`
- Production: Your web app's domain
- Device IPs: `http://10.71.50.53:*` (if needed)
3. **Test after server configuration** is updated
---
## Technical Details
**Why Mobile Works:**
- Native apps use platform HTTP clients (URLSession, HttpURLConnection)
- No browser, no CORS enforcement
**Why Web Fails:**
- Web browsers enforce Same-Origin Policy
- Requires server to send `Access-Control-Allow-Origin` header
- SignalR needs `Access-Control-Allow-Credentials: true`
**What the browser is blocking:**
```
Request: http://localhost:xxxxx → https://ms.hmg.com/nscapi
Response missing: Access-Control-Allow-Origin: http://localhost:xxxxx
Result: ❌ BLOCKED
```
---
**Date:** August 2, 2026
**Status:** ⚠️ SERVER CONFIGURATION REQUIRED