The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Use Go’s standard-library net/url package. Call url.Parse for ordinary absolute or relative URL references, and url.ParseRequestURI when the input is an HTTP request target. Parsing is only syntax handling: validate the scheme, host, and any other requirements your application has before using the result.
This guide shows complete code for both contexts, explains decoded versus escaped paths, strict query parsing, request-target formatting, relative-reference resolution, failure handling, and production concerns.
Choose the parser from the input context
The two commonly confused functions have different contracts. Parse accepts a URI reference, including relative references. ParseRequestURI applies HTTP request-target rules and assumes there is no fragment.
| Function | Use it for | Important behavior |
|---|---|---|
url.Parse |
General absolute or relative references | A string such as /images/logo.svg is valid. A host and path without a scheme can be ambiguous, so parsing does not prove that the value is an absolute URL. |
url.ParseRequestURI |
Values received as an HTTP request target, such as r.RequestURI |
Accepts an absolute URI or absolute path and assumes no fragment suffix. |
After either call, check the returned error. Then enforce application policy explicitly. For an absolute URL, require both Scheme and Host; for a relative link, require the fields appropriate to your use case.
#1 Best Overall
Parse a general URL reference
This function accepts both absolute and relative input. The validation below turns the parser into an “absolute URL only” helper:
package main
import (
"errors"
"fmt"
"net/url"
)
func parseAbsolute(raw string) (*url.URL, error) {
u, err := url.Parse(raw)
if err != nil {
return nil, fmt.Errorf("parse URL: %w", err)
}
if u.Scheme == "" || u.Host == "" {
return nil, errors.New("expected an absolute URL with scheme and host")
}
return u, nil
}
func main() {
u, err := parseAbsolute("https://example.com/docs/page?lang=en#install")
if err != nil {
panic(err)
}
fmt.Println("scheme:", u.Scheme)
fmt.Println("host:", u.Host)
fmt.Println("path:", u.Path)
fmt.Println("fragment:", u.Fragment)
}
If your feature intentionally accepts relative references, omit that final policy check and handle u.IsAbs(), u.Host, and other fields according to your rules. A successful Parse call is not an authorization or safety decision.
Parse an HTTP request target
Inside an HTTP handler, parse the request target supplied by the server:
func handler(w http.ResponseWriter, r *http.Request) {
u, err := url.ParseRequestURI(r.RequestURI)
if err != nil {
http.Error(w, "bad request target", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "path=%s query=%s", u.Path, u.RawQuery)
}
ParseRequestURI is appropriate because an HTTP request target is not necessarily an absolute URL. It accepts an absolute URI or an absolute path and rejects the fragment-style suffix that belongs to client-side navigation rather than an HTTP request target. For a value copied from a page, configuration file, or database, use Parse instead.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallRead URL components correctly
Decoded path versus escaped path
URL.Path is decoded. If the spelling of an escape matters, use EscapedPath():
u, err := url.Parse("https://example.com/foo%2fbar")
if err != nil {
panic(err)
}
fmt.Println(u.Path) // /foo/bar
fmt.Println(u.EscapedPath()) // /foo%2fbar
fmt.Println(u.String()) // https://example.com/foo%2fbar
The encoded slash (%2F) and a literal slash can have different meaning to a router, signature scheme, or object-store key. Do not compare or authorize using only Path when that distinction is significant. String() uses the escaped path representation while serializing the URL.
Host, user information, and ports
Use u.Host for the authority as written, u.Hostname() for the host without a port, and u.Port() for the port. If credentials are present, u.User exposes them; avoid logging u.String() without considering whether it could disclose a password.
Read and modify query parameters
Convenient access with Query
u, err := url.Parse("https://example.com/search?q=go&page=2")
if err != nil {
return err
}
values := u.Query()
fmt.Println(values.Get("q")) // go
fmt.Println(values["page"][0]) // 2
Query() returns url.Values, supports repeated keys, and is convenient when malformed pairs should not stop processing. It silently discards malformed query pairs, so it is not strict validation.
Recommended Free Tools
Surface malformed query data with ParseQuery
values, err := url.ParseQuery(u.RawQuery)
if err != nil {
return fmt.Errorf("invalid query: %w", err)
}
values.Set("page", "3")
u.RawQuery = values.Encode()
Use this path when clients must receive an error for malformed escaping or malformed key-value pairs. After changing values, assign the encoded result back to RawQuery. Encode produces canonical form ordering and escaping; do not assume it preserves the original byte-for-byte query spelling.
Produce the request URI
When an HTTP client or signing routine needs only the encoded path and query, call RequestURI():
u, err := url.Parse("https://example.org/path?foo=bar")
if err != nil {
return err
}
fmt.Println(u.RequestURI()) // /path?foo=bar
The result excludes scheme, host, user information, and fragment. It is the encoded path-and-query portion used in an HTTP request. For an empty path, Go may emit / as required by request formatting.
Resolve relative references against a base
Parse the base and reference separately, then resolve according to RFC 3986 rules:
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #4
base, err := url.Parse("https://example.com/docs/")
if err != nil {
return err
}
ref, err := url.Parse("../guide")
if err != nil {
return err
}
absolute := base.ResolveReference(ref)
fmt.Println(absolute.String()) // https://example.com/guide
The base must be absolute for a useful absolute result. A reference beginning with / replaces the base path, while one without a leading slash is resolved relative to the base directory. A reference containing its own scheme or host replaces those components. Treat externally supplied references as untrusted: resolution can legitimately produce a different host, so apply an allow-list before fetching.
A reusable, strict parsing helper
Centralizing policy prevents one call site from accepting relative input while another assumes an absolute network URL:
type ParsedURL struct {
URL *url.URL
}
func ParseHTTPS(raw string) (*ParsedURL, error) {
u, err := url.Parse(raw)
if err != nil {
return nil, fmt.Errorf("invalid URL syntax: %w", err)
}
if u.Scheme != "https" {
return nil, fmt.Errorf("scheme must be https, got %q", u.Scheme)
}
if u.Host == "" {
return nil, errors.New("URL has no host")
}
if u.User != nil {
return nil, errors.New("userinfo is not accepted")
}
return &ParsedURL{URL: u}, nil
}
Adapt the policy to your service. You might permit http for local development, reject fragments for server-side fetches, cap URL length, or allow only specific hostnames. Those are application decisions, not guarantees made by net/url.
Common errors and fixes
- “It parsed, but the host is empty.” You supplied a relative reference or an ambiguous host-and-path string. Require
SchemeandHostwhen an absolute URL is mandatory. - “
%2Fdisappeared.”Pathis decoded. UseEscapedPath()for the original escaped representation. - “Bad query input was accepted.”
Query()discards malformed pairs. ParseRawQuerywithurl.ParseQueryand handle its error. - “A fragment reached my server.” Fragments are client-side and are not sent in normal HTTP requests. Request-target parsing assumes no fragment; reject or remove one when your input contract is a request target.
- “The generated URL changed ordering or escaping.” Re-encoding through
url.Values.Encode()canonicalizes the query. Preserve the original raw string if byte-level fidelity is required. - “Relative links resolve to an unexpected domain.” Check the resolved URL’s scheme and hostname against an allow-list before making a request.
Performance, reliability, and security notes
net/urlis in the standard library and needs no third-party dependency. Parsing is normally inexpensive, but validate input size before accepting untrusted values.- Always check errors; never continue with a partially trusted URL after a failed parse.
- Do not treat syntactic validity as proof that a destination is reachable, safe, or authorized. Apply scheme, host, port, redirect, and network-policy checks separately.
- Use escaped forms for signing and request construction when the exact wire representation matters. Use decoded fields for user-facing path operations only when that is the intended semantics.
- Write tests for absolute URLs, relative references, repeated query keys, malformed escapes, encoded slashes, empty paths, fragments, Unicode, and userinfo.
Or skip the browser setup
If your goal is to obtain a clean screenshot of a parsed or resolved URL rather than operate a browser yourself, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—work with Claude, Cursor, and other MCP clients.
One GET request is enough:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for all options. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up free.
Best Value
Equivalent calls from Python and Node.js
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Frequently Asked Questions
Does url.Parse verify that a URL is reachable?
No. It parses syntax only. DNS, TLS, redirects, authentication, and application allow-lists must be handled separately.
Can I use ParseRequestURI for every URL?
Use it for HTTP request-target input. General links and configuration values should normally use url.Parse, which supports relative references and fragments.
Which field should I store for a URL?
Store the original string when exact fidelity matters, and retain the parsed URL for structured operations. Choose Path, EscapedPath(), or RequestURI() according to the consumer’s contract.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




