Created
June 3, 2025 09:35
-
-
Save sunmeat/9b3bf5ff128ca5561a791cc9e289a318 to your computer and use it in GitHub Desktop.
render.com example REACT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
App.jsx (client side): | |
import { useState, useRef } from 'react'; | |
const SERVER_URL = 'https://netserver-dkf4.onrender.com/send'; | |
function App() { | |
const [inputValue, setInputValue] = useState('5'); | |
const [isSending, setIsSending] = useState(false); | |
const [messages, setMessages] = useState([]); | |
const resultRef = useRef(null); | |
const inputRef = useRef(null); | |
const appendResult = (message, type) => { | |
setMessages((prev) => [...prev, { message, type }]); | |
setTimeout(() => { | |
if (resultRef.current) { | |
resultRef.current.scrollTop = resultRef.current.scrollHeight; | |
} | |
}, 0); | |
}; | |
const sendNumber = async () => { | |
if (isSending) return; | |
const input = inputValue.trim(); | |
if (!input) { | |
appendResult('Пожалуйста, введите число или "exit".', 'error'); | |
return; | |
} | |
if (input.toLowerCase() === 'exit') { | |
stopSending(); | |
return; | |
} | |
setIsSending(true); | |
appendResult('Отправка...', 'success'); | |
try { | |
const response = await fetch(SERVER_URL, { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'text/plain', | |
'Accept': 'text/plain', | |
}, | |
body: input, | |
}); | |
if (!response.ok) { | |
const errorText = await response.text(); | |
throw new Error(`Ошибка ${response.status}: ${errorText}`); | |
} | |
const result = await response.text(); | |
document.title = `Сервер ответил: ${result}`; | |
appendResult(`Сервер ответил: ${result}`, 'success'); | |
} catch (error) { | |
appendResult(`Ошибка отправки: ${error.message}`, 'error'); | |
} finally { | |
setIsSending(false); | |
setInputValue(''); | |
inputRef.current?.focus(); | |
} | |
}; | |
const stopSending = () => { | |
setIsSending(false); | |
appendResult('Отправка остановлена.', 'success'); | |
document.title = 'Отправка числа на сервер'; | |
}; | |
const handleKeyPress = (e) => { | |
if (e.key === 'Enter') { | |
sendNumber(); | |
} | |
}; | |
const styles = { | |
body: { | |
fontFamily: 'Arial, sans-serif', | |
backgroundColor: '#121212', | |
color: '#ffffff', | |
padding: '2rem', | |
margin: 0, | |
minHeight: '100vh', | |
}, | |
container: { | |
maxWidth: '600px', | |
margin: '0 auto', | |
backgroundColor: '#1e1e1e', | |
padding: '20px', | |
borderRadius: '10px', | |
}, | |
input: { | |
padding: '8px', | |
borderRadius: '5px', | |
border: 'none', | |
backgroundColor: '#2a2a2a', | |
color: '#ffffff', | |
width: '100%', | |
boxSizing: 'border-box', | |
marginBottom: '10px', | |
}, | |
button: { | |
padding: '0.5rem 1rem', | |
margin: '5px', | |
borderRadius: '5px', | |
border: 'none', | |
backgroundColor: '#1db954', | |
color: '#ffffff', | |
cursor: 'pointer', | |
fontSize: '16px', | |
}, | |
buttonHover: { | |
backgroundColor: '#1ed760', | |
}, | |
buttonDisabled: { | |
backgroundColor: '#555', | |
cursor: 'not-allowed', | |
}, | |
resultBox: { | |
margin: '20px 0', | |
padding: '10px', | |
border: '1px solid #444', | |
borderRadius: '5px', | |
textAlign: 'left', | |
maxHeight: '300px', | |
overflowY: 'auto', | |
}, | |
success: { | |
color: '#00FF00', | |
}, | |
error: { | |
color: '#FF5555', | |
}, | |
h2: { | |
textAlign: 'center', | |
}, | |
}; | |
return ( | |
<div style={styles.body}> | |
<div style={styles.container}> | |
<h2 style={styles.h2}>Отправка числа на сервер</h2> | |
<input | |
type="text" | |
placeholder="Введите число или 'exit'" | |
value={inputValue} | |
onChange={(e) => setInputValue(e.target.value)} | |
onKeyPress={handleKeyPress} | |
style={styles.input} | |
ref={inputRef} | |
/> | |
<button | |
style={{ ...styles.button, ...(isSending ? styles.buttonDisabled : {}) }} | |
onMouseOver={(e) => !isSending && (e.currentTarget.style.backgroundColor = styles.buttonHover.backgroundColor)} | |
onMouseOut={(e) => !isSending && (e.currentTarget.style.backgroundColor = styles.button.backgroundColor)} | |
onClick={sendNumber} | |
disabled={isSending} | |
> | |
Отправить | |
</button> | |
<button | |
style={{ ...styles.button, ...(!isSending ? styles.buttonDisabled : {}) }} | |
onMouseOver={(e) => isSending && (e.currentTarget.style.backgroundColor = styles.buttonHover.backgroundColor)} | |
onMouseOut={(e) => isSending && (e.currentTarget.style.backgroundColor = styles.button.backgroundColor)} | |
onClick={stopSending} | |
disabled={!isSending} | |
> | |
Остановить | |
</button> | |
<div style={styles.resultBox} ref={resultRef}> | |
{messages.map((msg, index) => ( | |
<div key={index} style={styles[msg.type]}> | |
{msg.message} | |
</div> | |
))} | |
</div> | |
</div> | |
</div> | |
); | |
} | |
export default App; | |
===================================================================================================== | |
https://github.com/sunmeat/NetServer/blob/master/Program.cs (server side): | |
using System; | |
using System.Net; | |
using System.Text; | |
using System.IO; | |
using System.Threading.Tasks; | |
class Program | |
{ | |
static async Task Main() | |
{ | |
string port = Environment.GetEnvironmentVariable("PORT") ?? "5000"; | |
string url = $"http://+:{port}/send/"; | |
HttpListener listener = new HttpListener(); | |
listener.Prefixes.Add(url); | |
listener.Start(); | |
Console.WriteLine($"Сервер запущен на {url}"); | |
while (true) | |
{ | |
var context = await listener.GetContextAsync(); | |
_ = Task.Run(() => ProcessRequest(context)); | |
} | |
} | |
static async Task ProcessRequest(HttpListenerContext context) | |
{ | |
HttpListenerRequest request = context.Request; | |
HttpListenerResponse response = context.Response; | |
// add CORS headers to all responses (for JavaScript example) | |
response.AddHeader("Access-Control-Allow-Origin", "*"); | |
response.AddHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); | |
response.AddHeader("Access-Control-Allow-Headers", "Content-Type"); | |
// handle preflight OPTIONS request (for JavaScript example) | |
if (request.HttpMethod == "OPTIONS") | |
{ | |
response.StatusCode = 200; | |
response.Close(); | |
return; | |
} | |
if (request.HttpMethod != "POST") | |
{ | |
response.StatusCode = 405; | |
await response.OutputStream.WriteAsync(Encoding.UTF8.GetBytes("Только POST-запросы")); | |
response.Close(); | |
return; | |
} | |
using var reader = new StreamReader(request.InputStream, Encoding.UTF8); | |
string numberStr = await reader.ReadToEndAsync(); | |
if (int.TryParse(numberStr, out int number)) | |
{ | |
int result = number + 1; | |
byte[] buffer = Encoding.UTF8.GetBytes(result.ToString()); | |
response.ContentType = "text/plain"; | |
response.ContentLength64 = buffer.Length; | |
await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); | |
Console.WriteLine($"Получено: {number}, отправлено: {result}"); | |
} | |
else | |
{ | |
response.StatusCode = 400; | |
await response.OutputStream.WriteAsync(Encoding.UTF8.GetBytes("Ошибка: ожидалось число.")); | |
} | |
response.Close(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment