Add Accept and User-Agent headers, improve HTML error detection

**Motivations:**
- Some NIP-95 endpoints require Accept and User-Agent headers
- Better diagnosis of HTML error responses (404, 403, 500)
- More detailed error messages for troubleshooting

**Root causes:**
- Missing Accept: application/json header may cause endpoints to return HTML
- Missing User-Agent header may cause some servers to reject requests
- HTML error pages need better detection and classification

**Correctifs:**
- Added Accept: application/json header to all requests
- Added User-Agent: zapwall.fr/1.0 header to all requests
- Improved HTML error detection with 404/403/500 classification
- Enhanced error messages with specific suggestions based on error type
- Increased body preview in logs from 200 to 500 characters for better diagnosis

**Evolutions:**
- None

**Pages affectées:**
- pages/api/nip95-upload.ts
This commit is contained in:
Nicolas Cantu 2026-01-05 22:50:37 +01:00
parent c7f8d301d5
commit cee363c598

View File

@ -82,6 +82,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const clientModule = isHttps ? https : http const clientModule = isHttps ? https : http
const headers = requestFormData.getHeaders() const headers = requestFormData.getHeaders()
// Add standard headers that some endpoints require
headers['Accept'] = 'application/json'
headers['User-Agent'] = 'zapwall.fr/1.0'
// Add NIP-98 Authorization header if token is provided // Add NIP-98 Authorization header if token is provided
if (authToken) { if (authToken) {
headers['Authorization'] = `Nostr ${authToken}` headers['Authorization'] = `Nostr ${authToken}`
@ -246,23 +250,50 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// Check if response is HTML (error page) instead of JSON // Check if response is HTML (error page) instead of JSON
const trimmedBody = response.body.trim() const trimmedBody = response.body.trim()
const isHtml = trimmedBody.startsWith('<!DOCTYPE') || trimmedBody.startsWith('<html') || trimmedBody.startsWith('<!') const isHtml = trimmedBody.startsWith('<!DOCTYPE') || trimmedBody.startsWith('<html') || trimmedBody.startsWith('<!')
if (isHtml) { if (isHtml) {
// Try to extract error message from HTML if possible // Try to extract error message from HTML if possible
const titleMatch = response.body.match(/<title[^>]*>([^<]+)<\/title>/i) const titleMatch = response.body.match(/<title[^>]*>([^<]+)<\/title>/i)
const h1Match = response.body.match(/<h1[^>]*>([^<]+)<\/h1>/i) const h1Match = response.body.match(/<h1[^>]*>([^<]+)<\/h1>/i)
const errorText = titleMatch?.[1] || h1Match?.[1] || 'HTML error page returned' const errorText = titleMatch?.[1] || h1Match?.[1] || 'HTML error page returned'
// Check if it's a 404 or other error page
const is404 = response.body.includes('404') || response.body.includes('Not Found') || titleMatch?.[1]?.includes('404')
const is403 = response.body.includes('403') || response.body.includes('Forbidden') || titleMatch?.[1]?.includes('403')
const is500 = response.body.includes('500') || response.body.includes('Internal Server Error') || titleMatch?.[1]?.includes('500')
console.error('NIP-95 proxy HTML response error:', { console.error('NIP-95 proxy HTML response error:', {
targetEndpoint, targetEndpoint,
finalUrl: currentUrl.toString(), finalUrl: currentUrl.toString(),
status: response.statusCode, status: response.statusCode,
errorText, errorText,
bodyPreview: response.body.substring(0, 200), is404,
is403,
is500,
bodyPreview: response.body.substring(0, 500),
contentType: 'HTML (expected JSON)',
suggestion: is404
? 'The endpoint URL may be incorrect or the endpoint does not exist'
: is403
? 'The endpoint may require authentication or have access restrictions'
: is500
? 'The endpoint server encountered an error'
: 'The endpoint may not be a valid NIP-95 upload endpoint or may require specific headers',
}) })
let userMessage = `Endpoint returned an HTML error page instead of JSON`
if (is404) {
userMessage = `Endpoint not found (404). The URL may be incorrect: ${currentUrl.toString()}`
} else if (is403) {
userMessage = `Access forbidden (403). The endpoint may require authentication or have restrictions.`
} else if (is500) {
userMessage = `Server error (500). The endpoint server encountered an error.`
} else {
userMessage = `Endpoint returned an HTML error page instead of JSON. The endpoint may be unavailable, the URL may be incorrect, or specific headers may be required. Error: ${errorText}`
}
return res.status(500).json({ return res.status(500).json({
error: `Endpoint returned an HTML error page instead of JSON. The endpoint may be unavailable or the URL may be incorrect. Error: ${errorText}`, error: userMessage,
}) })
} }