.NET环境下Selenium部署生产环境后Chrome进程无法启动
ASP.NET Web API部署后Selenium无法启动Chrome进程的解决方法
问题描述
本地运行ASP.NET Web API中使用Selenium WebDriver的代码正常,但部署到生产环境后提示无法创建Chrome进程。已将对应版本的WebDriver.exe部署至wwwroot,也尝试过更新Selenium、复制chrome.exe到wwwroot并指定二进制路径,但问题仍未解决。
相关代码
ChromeOptions options = new ChromeOptions(); options.AddArgument("--no-sandbox"); options.AddArgument("--headless"); options.AddArgument("--ignore-ssl-errors=true"); options.AddArgument("--ignore-certificate-errors"); options.AddArgument("--window-size=1920x1080"); options.AddArgument("--disable-gpu"); options.AddUserProfilePreference("download.default_directory", "Downloads"); options.AddUserProfilePreference("download.prompt_for_download", false); options.AddUserProfilePreference("safebrowsing.enabled", false); string chromeDriverPath = @"C:\Users\Gentrit\source\repos\Azon\Azon\bin\Debug\net8.0"; using (var driver = new ChromeDriver(_hostingEnvironment.WebRootPath, options)){ // 错误在此处抛出,无法创建chrome进程 }
完整错误信息
[Error] Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer: Connection ID "18014398527467168636", Request ID "4000237f-0004-fa00-b63f-84710c7967bb": An unhandled exception was thrown by the application. OpenQA.Selenium.WebDriverException: unknown error: Failed to create Chrome process.at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)at OpenQA.Selenium.WebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)at OpenQA.Selenium.WebDriver.StartSession(ICapabilities desiredCapabilities)at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)at OpenQA.Selenium.Chromium.ChromiumDriver..ctor(ChromiumDriverService service, ChromiumOptions options, TimeSpan commandTimeout)at OpenQA.Selenium.Chrome.ChromeDriver..ctor(ChromeDriverService service, ChromeOptions options, TimeSpan commandTimeout)at OpenQA.Selenium.Chrome.ChromeDriver..ctor(String chromeDriverDirectory, ChromeOptions options, TimeSpan commandTimeout)at OpenQA.Selenium.Chrome.ChromeDriver..ctor(String chromeDriverDirectory, ChromeOptions options)at Azon.Controllers.HomeController.UploadImageAsync(IFormFile image) in C:\Users\Gentrit\source\repos\Azon\Azon\Controllers\HomeController.cs:line 100at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)at Program.<<<Main>$>b__0_10>d.MoveNext() in C:\Users\Gentrit\source\repos\Azon\Azon\Program.cs:line 151--- End of stack trace from previous location ---at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()
排查与解决步骤
1. 修正ChromeDriver路径配置
代码中chromeDriverPath是本地调试路径,生产环境完全无效。需确保初始化ChromeDriver时传入的路径下存在对应版本的chromedriver.exe,并避免硬编码本地路径:
// 构建Web根目录下的driver路径 string chromeDriverPath = Path.Combine(_hostingEnvironment.WebRootPath, "drivers"); // 确保目录存在,避免路径不存在报错 Directory.CreateDirectory(chromeDriverPath);
2. 补充服务器适配的Chrome启动参数
生产环境多为无桌面的服务器环境,需添加更多适配参数:
ChromeOptions options = new ChromeOptions(); options.AddArgument("--no-sandbox"); options.AddArgument("--headless=new"); // 新版无头模式兼容性更强 options.AddArgument("--ignore-ssl-errors=true"); options.AddArgument("--ignore-certificate-errors"); options.AddArgument("--window-size=1920x1080"); options.AddArgument("--disable-gpu"); options.AddArgument("--disable-dev-shm-usage"); // 解决共享内存不足问题 options.AddArgument("--remote-debugging-port=9222"); // 避免端口冲突 options.AddArgument("--no-first-run"); // 跳过首次运行配置 options.AddArgument("--disable-extensions"); // 禁用扩展减少启动负载 // 下载路径改为绝对路径,避免相对路径在生产环境失效 string downloadPath = Path.Combine(_hostingEnvironment.ContentRootPath, "Downloads"); Directory.CreateDirectory(downloadPath); options.AddUserProfilePreference("download.default_directory", downloadPath); options.AddUserProfilePreference("download.prompt_for_download", false); options.AddUserProfilePreference("safebrowsing.enabled", false);
3. 明确指定Chrome二进制文件路径
若生产环境未全局安装Chrome,需指定完整的chrome.exe路径(需部署Chrome完整目录,而非仅单个exe文件):
// 假设Chrome部署在Web根目录的Chrome文件夹下 string chromeBinaryPath = Path.Combine(_hostingEnvironment.WebRootPath, "Chrome", "chrome.exe"); options.BinaryLocation = chromeBinaryPath;
4. 检查应用程序池权限
- 确保IIS应用程序池的运行账户(如
ApplicationPoolIdentity或自定义账户)拥有:chromedriver.exe和Chrome目录的读取权限- 下载目录的写入权限
- 创建进程的权限(需在服务器本地安全策略中配置)
- 测试阶段可临时将应用程序池切换为
LocalSystem验证权限问题,生产环境需使用权限最小化的自定义账户。
5. 验证版本匹配性
确保Chrome版本与ChromeDriver版本完全对应,可通过代码输出版本信息排查:
// 输出ChromeDriver版本 Console.WriteLine($"ChromeDriver Version: {ChromeDriverService.CreateDefaultService().DriverVersion}");
6. 启用ChromeDriver日志定位问题
配置日志输出,查看具体启动失败原因:
var service = ChromeDriverService.CreateDefaultService(chromeDriverPath); service.LogPath = Path.Combine(_hostingEnvironment.ContentRootPath, "chromedriver.log"); service.EnableVerboseLogging = true; using (var driver = new ChromeDriver(service, options)) { // 业务逻辑代码 }
查看生成的chromedriver.log,里面会包含Chrome启动失败的具体细节(如文件缺失、权限不足、依赖缺失等)。
7. 检查服务器依赖项
Windows服务器运行Chrome需确保安装:
- 对应版本的Visual C++ Redistributable Packages
- .NET Framework 4.8或更高版本(适配旧版ChromeDriver)
- 关闭或配置安全软件(防火墙、杀毒软件)允许Chrome和ChromeDriver运行
内容的提问来源于stack exchange,提问作者Gentrit Cunaj
相关产品推荐
相关产品推荐

