Skip to content

got 502 with vite server: [ExternalAssetHandler] Proxy error error="dial tcp [::1]:9245 #4556

@EddieHuang-01

Description

@EddieHuang-01

Description

in my case of project (vite+vue + both wailsv2&wailsv3, using a lot dynamic-import), i met a lot 502 logs like below:

Sep 4 19:00:06.139 INF Asset Request: windowName="" windowID=4 code=502 method=GET path=/node_modules/.vite/deps/chunk-JD7FDHYW.js duration=3.5337ms Sep 4 19:00:06.138 ERR 
[ExternalAssetHandler] Proxy error error="dial tcp [::1]:9245: connectex: No connection could be made because the target machine actively refused it."

the devtools of wails window also show a lot of failures

GET http://wails.localhost:9245/node_modules/.vite/deps/chunk-VEN36MIW.js?v=c956c98c net::ERR_ABORTED 502 (Bad Gateway)

I tried to visit http://wails.localhost:34115/ in Chrome but it went well with no errors,.
I gave these info to AI, AI told me to modify wails3\internal\assetserver\build_dev.go to:

//go:build !production

package assetserver

import (
	"context"
	_ "embed"
	"io/fs"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"time"
)

type retryTransport struct {
	base       http.RoundTripper
	maxRetries int
	delay      time.Duration
}

func (t *retryTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	var resp *http.Response
	var err error
	for i := 0; i < t.maxRetries; i++ {
		resp, err = t.base.RoundTrip(req)
		if err == nil {
			return resp, nil
		}
		time.Sleep(t.delay)
	}
	return resp, err
}

func NewAssetFileServer(vfs fs.FS) http.Handler {
	devServerURL := GetDevServerURL()
	if devServerURL == "" {
		return newAssetFileServerFS(vfs)
	}
	dialer := &net.Dialer{
		Timeout:   5 * time.Second,
		KeepAlive: 30 * time.Second,
	}
	parsedURL, err := url.Parse(devServerURL)
	if err != nil {
		return http.HandlerFunc(
			func(rw http.ResponseWriter, req *http.Request) {
				logError(req.Context(), "[ExternalAssetHandler] Invalid FRONTEND_DEVSERVER_URL. Should be valid URL", "error", err.Error())
				http.Error(rw, err.Error(), http.StatusInternalServerError)
			})

	}

	proxy := httputil.NewSingleHostReverseProxy(parsedURL)
	proxy.Transport = &retryTransport{
		base: &http.Transport{
			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
				return dialer.DialContext(ctx, "tcp4", addr)
			},
		},
		maxRetries: 3,
		delay:      200 * time.Millisecond,
	}
	proxy.ErrorHandler = func(rw http.ResponseWriter, r *http.Request, err error) {
		logError(r.Context(), "[ExternalAssetHandler] Proxy error", "error", err.Error())
		rw.WriteHeader(http.StatusBadGateway)
	}

	return proxy
}

func GetDevServerURL() string {
	return os.Getenv("FRONTEND_DEVSERVER_URL")
}

and it works fine now, but I'm not sure if this is the best way to handle the problem

To Reproduce

start wails with a vite project with a lot pages and dynamic-imports

Expected behaviour

get rid of those 502

Screenshots

in devtools of wails window:

Image

in log of command wails3 dev:

Image

Attempted Fixes

modify build_dev.go :

type retryTransport struct {
	base       http.RoundTripper
	maxRetries int
	delay      time.Duration
}

func (t *retryTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	var resp *http.Response
	var err error
	for i := 0; i < t.maxRetries; i++ {
		resp, err = t.base.RoundTrip(req)
		if err == nil {
			return resp, nil
		}
		time.Sleep(t.delay)
	}
	return resp, err
}

func NewAssetFileServer(vfs fs.FS) http.Handler {
	devServerURL := GetDevServerURL()
	if devServerURL == "" {
		return newAssetFileServerFS(vfs)
	}
	dialer := &net.Dialer{
		Timeout:   5 * time.Second,
		KeepAlive: 30 * time.Second,
	}
	parsedURL, err := url.Parse(devServerURL)
	if err != nil {
		return http.HandlerFunc(
			func(rw http.ResponseWriter, req *http.Request) {
				logError(req.Context(), "[ExternalAssetHandler] Invalid FRONTEND_DEVSERVER_URL. Should be valid URL", "error", err.Error())
				http.Error(rw, err.Error(), http.StatusInternalServerError)
			})

	}

	proxy := httputil.NewSingleHostReverseProxy(parsedURL)
	proxy.Transport = &retryTransport{
		base: &http.Transport{
			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
				return dialer.DialContext(ctx, "tcp4", addr)
			},
		},
		maxRetries: 3,
		delay:      200 * time.Millisecond,
	}

	proxy.ErrorHandler = func(rw http.ResponseWriter, r *http.Request, err error) {
		logError(r.Context(), "[ExternalAssetHandler] Proxy error", "error", err.Error())
		rw.WriteHeader(http.StatusBadGateway)
	}

	return proxy
}

System Details

┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
| Name              | Windows 10 Pro                                                                                     |
| Version           | 2009 (Build: 26100)                                                                                |
| ID                | 24H2                                                                                               |
| Branding          | Windows 11 专业版                                                                                  |
| Platform          | windows                                                                                            |
| Architecture      | amd64                                                                                              |
| Go WebView2Loader | true                                                                                               |
| WebView2 Version  | 139.0.3405.125                                                                                     |
| CPU               | AMD Ryzen 5 7500F 6-Core Processor                                                                 |
| GPU 1             | OrayIddDriver Device (Shanghai Best Oray Information Technology Co., Ltd.) - Driver: 17.50.19.949  |
| GPU 2             | NVIDIA GeForce RTX 3080 (NVIDIA) - Driver: 32.0.15.6094                                            |
| Memory            | 32GB                                                                                               |
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

# Build Environment

┌────────────────────────────────┐
| Wails CLI    | v3.0.0-alpha.25 |
| Go Version   | go1.24.5        |
| -buildmode   | exe             |
| -compiler    | gc              |
| CGO_CFLAGS   |                 |
| CGO_CPPFLAGS |                 |
| CGO_CXXFLAGS |                 |
| CGO_ENABLED  | 1               |
| CGO_LDFLAGS  |                 |
| GOAMD64      | v1              |
| GOARCH       | amd64           |
| GOOS         | windows         |
└────────────────────────────────┘

# Dependencies

┌────────────────────────────────────────────┐
| npm                        | 10.9.2        |
| NSIS                       | v3.11         |
| MakeAppx.exe (Windows SDK) | Not Installed |
| MSIX Packaging Tool        | Not Installed |
| SignTool.exe (Windows SDK) | Not Installed |
|                                            |
└───────── * - Optional Dependency ──────────┘

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't workingWindowsawaiting feedbackMore information is required from the requestor

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions