我在C#中编写HTTP服务器。

当我尝试执行功能时 HttpListener.Start() 我得到一个 HttpListenerException

“拒绝访问”。

当我在Windows 7中以管理模式运行该应用程序时,它可以正常运行。

我可以在没有管理模式的情况下运行它吗?如果是的话?如果没有,如何在开始运行后将应用程序更改为管理模式?

using System;
using System.Net;

namespace ConsoleApplication1
{
    class Program
    {
        private HttpListener httpListener = null;

        static void Main(string[] args)
        {
            Program p = new Program();
            p.Server();
        }

        public void Server()
        {
            this.httpListener = new HttpListener();

            if (httpListener.IsListening)
                throw new InvalidOperationException("Server is currently running.");

            httpListener.Prefixes.Clear();
            httpListener.Prefixes.Add("http://*:4444/");

            try
            {
                httpListener.Start(); //Throws Exception
            }
            catch (HttpListenerException ex)
            {
                if (ex.Message.Contains("Access is denied"))
                {
                    return;
                }
                else
                {
                    throw;
                }
            }
        }
    }
}
有帮助吗?

解决方案

是的,您可以在非ADMIN模式下运行HTTPLISTENER。您需要做的就是授予特定URL的权限。例如

netsh http add urlacl url=http://+:80/MyUri user=DOMAIN\user

文档是 这里.

其他提示

我可以在没有管理模式的情况下运行它吗?如果是的话?如果没有,如何在开始运行后将应用程序更改为管理模式?

您不能,它必须从特权提高开始。您可以使用 runas 动词,这将促使用户切换到管理模式

static void RestartAsAdmin()
{
    var startInfo = new ProcessStartInfo("yourApp.exe") { Verb = "runas" };
    Process.Start(startInfo);
    Environment.Exit(0);
}

编辑:实际上,这是不正确的; httplistener可以在没有提高特权的情况下运行,但是您需要允许您要收听的URL。看 达雷尔·米勒(Darrel Miller)的答案 有关详细信息。

如果您使用 http://localhost:80/ 作为前缀,您可以收听无需管理特权的HTTP请求。

语法对我来说是错误的,您必须包括报价:

netsh http add urlacl url="http://+:4200/" user=everyone

否则我收到了“参数不正确”

如果您想使用标志“用户=每个人”,则需要将其调整为系统语言。在英语中,如下所述:

netsh http add urlacl url=http://+:80/ user=Everyone

在德语中,它将是:

netsh http add urlacl url=http://+:80/ user=Jeder

作为不需要高程或网络的替代方案,您也可以使用tcplistener。

以下是此样本的修改摘录:https://github.com/googlesamples/oauth-apps-for-windows/tree/master/oauthdesktopapp

// Generates state and PKCE values.
string state = randomDataBase64url(32);
string code_verifier = randomDataBase64url(32);
string code_challenge = base64urlencodeNoPadding(sha256(code_verifier));
const string code_challenge_method = "S256";

// Creates a redirect URI using an available port on the loopback address.
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
string redirectURI = string.Format("http://{0}:{1}/", IPAddress.Loopback, ((IPEndPoint)listener.LocalEndpoint).Port);
output("redirect URI: " + redirectURI);

// Creates the OAuth 2.0 authorization request.
string authorizationRequest = string.Format("{0}?response_type=code&scope=openid%20profile&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
    authorizationEndpoint,
    System.Uri.EscapeDataString(redirectURI),
    clientID,
    state,
    code_challenge,
    code_challenge_method);

// Opens request in the browser.
System.Diagnostics.Process.Start(authorizationRequest);

// Waits for the OAuth authorization response.
var client = await listener.AcceptTcpClientAsync();

// Read response.
var response = ReadString(client);

// Brings this app back to the foreground.
this.Activate();

// Sends an HTTP response to the browser.
WriteStringAsync(client, "<html><head><meta http-equiv='refresh' content='10;url=https://google.com'></head><body>Please close this window and return to the app.</body></html>").ContinueWith(t =>
{
    client.Dispose();
    listener.Stop();

    Console.WriteLine("HTTP server stopped.");
});

// TODO: Check the response here to get the authorization code and verify the code challenge

读写方法是:

private string ReadString(TcpClient client)
{
    var readBuffer = new byte[client.ReceiveBufferSize];
    string fullServerReply = null;

    using (var inStream = new MemoryStream())
    {
        var stream = client.GetStream();

        while (stream.DataAvailable)
        {
            var numberOfBytesRead = stream.Read(readBuffer, 0, readBuffer.Length);
            if (numberOfBytesRead <= 0)
                break;

            inStream.Write(readBuffer, 0, numberOfBytesRead);
        }

        fullServerReply = Encoding.UTF8.GetString(inStream.ToArray());
    }

    return fullServerReply;
}

private Task WriteStringAsync(TcpClient client, string str)
{
    return Task.Run(() =>
    {
        using (var writer = new StreamWriter(client.GetStream(), new UTF8Encoding(false)))
        {
            writer.Write("HTTP/1.0 200 OK");
            writer.Write(Environment.NewLine);
            writer.Write("Content-Type: text/html; charset=UTF-8");
            writer.Write(Environment.NewLine);
            writer.Write("Content-Length: " + str.Length);
            writer.Write(Environment.NewLine);
            writer.Write(Environment.NewLine);
            writer.Write(str);
        }
    });
}

如果将应用程序清单添加到项目中,则可以以管理员的身份开始应用程序。

只需在项目中添加新项目,然后选择“应用清单文件”即可。更改 <requestedExecutionLevel> 元素到:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

默认情况下,Windows定义了每个人都可以使用的以下前缀:http://+:80/temorary_listen_addresses/

因此您可以注册您的 HttpListener 通过:

Prefixes.Add("http://+:80/Temporary_Listen_Addresses/" + Guid.NewGuid().ToString("D") + "/";

有时,这会导致Skype之类的软件问题,这些软件将尝试使用端口80的默认情况下。

httpListener.Prefixes.Add("http://*:4444/");

您使用“*”,因此执行CMD为管理员

netsh http add urlacl url=http://*:4444/ user=username

无用 +,必须使用 *,因为您规格 *:4444〜。

https://msdn.microsoft.com/en-us/library/system.net.httplistener.aspx

我也遇到了类似的问题。如果您已经保留了URL,那么您必须首先删除在非管理模式下运行的URL,否则将失败,而访问是拒绝的错误。

netsh http delete urlacl url=http://+:80

Netsh需要管理权

您可以通过设置imageWriteExceptions来解决该问题,而无需管理员权利:

listener.IgnoreWriteExceptions = True
listener.Start()
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top